1 // Copyright 2023 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_MOQT_SUBSCRIBE_WINDOWS_H 6 #define QUICHE_QUIC_MOQT_SUBSCRIBE_WINDOWS_H 7 8 #include <cstdint> 9 #include <optional> 10 #include <vector> 11 12 #include "absl/container/flat_hash_map.h" 13 #include "absl/container/node_hash_map.h" 14 #include "quiche/quic/moqt/moqt_messages.h" 15 #include "quiche/common/platform/api/quiche_export.h" 16 #include "quiche/web_transport/web_transport.h" 17 18 namespace moqt { 19 20 // Classes to track subscriptions to local tracks: the sequence numbers 21 // subscribed, the streams involved, and the subscribe IDs. 22 class QUICHE_EXPORT SubscribeWindow { 23 public: 24 // Creates a half-open window. SubscribeWindow(uint64_t subscribe_id,MoqtForwardingPreference forwarding_preference,uint64_t start_group,uint64_t start_object)25 SubscribeWindow(uint64_t subscribe_id, 26 MoqtForwardingPreference forwarding_preference, 27 uint64_t start_group, uint64_t start_object) 28 : subscribe_id_(subscribe_id), 29 start_({start_group, start_object}), 30 forwarding_preference_(forwarding_preference) {} 31 32 // Creates a closed window. SubscribeWindow(uint64_t subscribe_id,MoqtForwardingPreference forwarding_preference,uint64_t start_group,uint64_t start_object,uint64_t end_group,uint64_t end_object)33 SubscribeWindow(uint64_t subscribe_id, 34 MoqtForwardingPreference forwarding_preference, 35 uint64_t start_group, uint64_t start_object, 36 uint64_t end_group, uint64_t end_object) 37 : subscribe_id_(subscribe_id), 38 start_({start_group, start_object}), 39 end_(FullSequence(end_group, end_object)), 40 forwarding_preference_(forwarding_preference) {} 41 subscribe_id()42 uint64_t subscribe_id() const { return subscribe_id_; } 43 44 bool InWindow(const FullSequence& seq) const; 45 46 // Returns the stream to send |sequence| on, if already opened. 47 std::optional<webtransport::StreamId> GetStreamForSequence( 48 FullSequence sequence) const; 49 50 // Records what stream is being used for a track, group, or object depending 51 // on |forwarding_preference|. Triggers QUIC_BUG if already assigned. 52 void AddStream(uint64_t group_id, uint64_t object_id, 53 webtransport::StreamId stream_id); 54 55 void RemoveStream(uint64_t group_id, uint64_t object_id); 56 57 private: 58 // Converts an object sequence number into one that matches the way that 59 // stream IDs are being mapped. (See the comment for send_streams_ below.) 60 FullSequence SequenceToIndex(FullSequence sequence) const; 61 62 const uint64_t subscribe_id_; 63 const FullSequence start_; 64 const std::optional<FullSequence> end_ = std::nullopt; 65 // Store open streams for this subscription. If the forwarding preference is 66 // kTrack, there is one entry under sequence (0, 0). If kGroup, each entry is 67 // under (group, 0). If kObject, it's tracked under the full sequence. If 68 // kDatagram, the map is empty. 69 absl::flat_hash_map<FullSequence, webtransport::StreamId> send_streams_; 70 // The forwarding preference for this track; informs how the streams are 71 // mapped. 72 const MoqtForwardingPreference forwarding_preference_; 73 }; 74 75 // Class to keep track of the sequence number blocks to which a peer is 76 // subscribed. 77 class QUICHE_EXPORT MoqtSubscribeWindows { 78 public: MoqtSubscribeWindows(MoqtForwardingPreference forwarding_preference)79 MoqtSubscribeWindows(MoqtForwardingPreference forwarding_preference) 80 : forwarding_preference_(forwarding_preference) {} 81 82 // Returns a vector of subscribe IDs that apply to the object. They will be in 83 // reverse order of the AddWindow calls. 84 std::vector<SubscribeWindow*> SequenceIsSubscribed(FullSequence sequence); 85 86 // |start_group| and |start_object| must be absolute sequence numbers. An 87 // optimization could consolidate overlapping subscribe windows. AddWindow(uint64_t subscribe_id,uint64_t start_group,uint64_t start_object)88 void AddWindow(uint64_t subscribe_id, uint64_t start_group, 89 uint64_t start_object) { 90 windows_.emplace(subscribe_id, 91 SubscribeWindow(subscribe_id, forwarding_preference_, 92 start_group, start_object)); 93 } AddWindow(uint64_t subscribe_id,uint64_t start_group,uint64_t start_object,uint64_t end_group,uint64_t end_object)94 void AddWindow(uint64_t subscribe_id, uint64_t start_group, 95 uint64_t start_object, uint64_t end_group, 96 uint64_t end_object) { 97 windows_.emplace( 98 subscribe_id, 99 SubscribeWindow(subscribe_id, forwarding_preference_, start_group, 100 start_object, end_group, end_object)); 101 } RemoveWindow(uint64_t subscribe_id)102 void RemoveWindow(uint64_t subscribe_id) { windows_.erase(subscribe_id); } 103 IsEmpty()104 bool IsEmpty() const { return windows_.empty(); } 105 GetWindow(uint64_t subscribe_id)106 SubscribeWindow* GetWindow(uint64_t subscribe_id) { 107 auto it = windows_.find(subscribe_id); 108 if (it == windows_.end()) { 109 return nullptr; 110 } 111 return &it->second; 112 } 113 114 private: 115 // Indexed by Subscribe ID. 116 absl::node_hash_map<uint64_t, SubscribeWindow> windows_; 117 const MoqtForwardingPreference forwarding_preference_; 118 }; 119 120 } // namespace moqt 121 122 #endif // QUICHE_QUIC_MOQT_SUBSCRIBE_WINDOWS_H 123