blob: 1236a786df66c1ce32393a283d6e516c1b9cdf7c [file] [log] [blame]
Johannes Kron746dd0d2019-06-20 13:37:521/*
2 * Copyright 2019 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#ifndef PC_USED_IDS_H_
11#define PC_USED_IDS_H_
12
13#include <set>
14#include <vector>
15
16#include "api/rtp_parameters.h"
17#include "media/base/codec.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
20
21namespace cricket {
22template <typename IdStruct>
23class UsedIds {
24 public:
25 UsedIds(int min_allowed_id, int max_allowed_id)
26 : min_allowed_id_(min_allowed_id),
27 max_allowed_id_(max_allowed_id),
28 next_id_(max_allowed_id) {}
29 virtual ~UsedIds() {}
30
Artem Titov880fa812021-07-30 20:30:2331 // Loops through all Id in `ids` and changes its id if it is
Johannes Kron746dd0d2019-06-20 13:37:5232 // already in use by another IdStruct. Call this methods with all Id
33 // in a session description to make sure no duplicate ids exists.
34 // Note that typename Id must be a type of IdStruct.
35 template <typename Id>
36 void FindAndSetIdUsed(std::vector<Id>* ids) {
37 for (const Id& id : *ids) {
38 FindAndSetIdUsed(&id);
39 }
40 }
41
Artem Titov880fa812021-07-30 20:30:2342 // Finds and sets an unused id if the `idstruct` id is already in use.
Johannes Kron746dd0d2019-06-20 13:37:5243 void FindAndSetIdUsed(IdStruct* idstruct) {
44 const int original_id = idstruct->id;
45 int new_id = idstruct->id;
46
47 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
48 // If the original id is not in range - this is an id that can't be
49 // dynamically changed.
50 return;
51 }
52
53 if (IsIdUsed(original_id)) {
54 new_id = FindUnusedId();
Tommi0428f952022-01-18 11:58:2555 // Duplicate id found. Reassign from the original id to the new.
Johannes Kron746dd0d2019-06-20 13:37:5256 idstruct->id = new_id;
57 }
58 SetIdUsed(new_id);
59 }
60
61 protected:
Philipp Hancke64a79c72021-05-10 15:28:3762 virtual bool IsIdUsed(int new_id) {
63 return id_set_.find(new_id) != id_set_.end();
64 }
Johannes Kron746dd0d2019-06-20 13:37:5265 const int min_allowed_id_;
66 const int max_allowed_id_;
67
68 private:
69 // Returns the first unused id in reverse order.
70 // This hopefully reduces the risk of more collisions. We want to change the
71 // default ids as little as possible. This function is virtual and can be
72 // overriden if the search for unused IDs should follow a specific pattern.
73 virtual int FindUnusedId() {
74 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
75 --next_id_;
76 }
77 RTC_DCHECK(next_id_ >= min_allowed_id_);
78 return next_id_;
79 }
80
81 void SetIdUsed(int new_id) {
82 RTC_DCHECK(new_id >= min_allowed_id_);
83 RTC_DCHECK(new_id <= max_allowed_id_);
84 RTC_DCHECK(!IsIdUsed(new_id));
85 id_set_.insert(new_id);
86 }
87 int next_id_;
88 std::set<int> id_set_;
89};
90
91// Helper class used for finding duplicate RTP payload types among audio, video
92// and data codecs. When bundle is used the payload types may not collide.
93class UsedPayloadTypes : public UsedIds<Codec> {
94 public:
95 UsedPayloadTypes()
Philipp Hancke64a79c72021-05-10 15:28:3796 : UsedIds<Codec>(kFirstDynamicPayloadTypeLowerRange,
97 kLastDynamicPayloadTypeUpperRange) {}
98
99 protected:
100 bool IsIdUsed(int new_id) override {
101 // Range marked for RTCP avoidance is "used".
102 if (new_id > kLastDynamicPayloadTypeLowerRange &&
103 new_id < kFirstDynamicPayloadTypeUpperRange)
104 return true;
105 return UsedIds<Codec>::IsIdUsed(new_id);
106 }
Johannes Kron746dd0d2019-06-20 13:37:52107
108 private:
Philipp Hancke64a79c72021-05-10 15:28:37109 static const int kFirstDynamicPayloadTypeLowerRange = 35;
Philipp Hanckeb412efd2021-05-25 07:03:19110 static const int kLastDynamicPayloadTypeLowerRange = 63;
Philipp Hancke64a79c72021-05-10 15:28:37111
112 static const int kFirstDynamicPayloadTypeUpperRange = 96;
113 static const int kLastDynamicPayloadTypeUpperRange = 127;
Johannes Kron746dd0d2019-06-20 13:37:52114};
115
116// Helper class used for finding duplicate RTP Header extension ids among
117// audio and video extensions.
118class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
119 public:
120 enum class IdDomain {
121 // Only allocate IDs that fit in one-byte header extensions.
122 kOneByteOnly,
123 // Prefer to allocate one-byte header extension IDs, but overflow to
124 // two-byte if none are left.
125 kTwoByteAllowed,
126 };
127
128 explicit UsedRtpHeaderExtensionIds(IdDomain id_domain)
129 : UsedIds<webrtc::RtpExtension>(
130 webrtc::RtpExtension::kMinId,
131 id_domain == IdDomain::kTwoByteAllowed
132 ? webrtc::RtpExtension::kMaxId
133 : webrtc::RtpExtension::kOneByteHeaderExtensionMaxId),
134 id_domain_(id_domain),
135 next_extension_id_(webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
136 }
137
138 private:
139 // Returns the first unused id in reverse order from the max id of one byte
140 // header extensions. This hopefully reduce the risk of more collisions. We
141 // want to change the default ids as little as possible. If no unused id is
142 // found and two byte header extensions are enabled (i.e.,
Artem Titov880fa812021-07-30 20:30:23143 // `extmap_allow_mixed_` is true), search for unused ids from 15 to 255.
Johannes Kron746dd0d2019-06-20 13:37:52144 int FindUnusedId() override {
145 if (next_extension_id_ <=
146 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
147 // First search in reverse order from the max id of one byte header
148 // extensions.
149 while (IsIdUsed(next_extension_id_) &&
150 next_extension_id_ >= min_allowed_id_) {
151 --next_extension_id_;
152 }
153 }
154
155 if (id_domain_ == IdDomain::kTwoByteAllowed) {
156 if (next_extension_id_ < min_allowed_id_) {
157 // We have searched among all one-byte IDs without finding an unused ID,
158 // continue at the first two-byte ID.
159 next_extension_id_ =
160 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId + 1;
161 }
162
163 if (next_extension_id_ >
164 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
165 while (IsIdUsed(next_extension_id_) &&
166 next_extension_id_ <= max_allowed_id_) {
167 ++next_extension_id_;
168 }
169 }
170 }
171 RTC_DCHECK(next_extension_id_ >= min_allowed_id_);
172 RTC_DCHECK(next_extension_id_ <= max_allowed_id_);
173 return next_extension_id_;
174 }
175
176 const IdDomain id_domain_;
177 int next_extension_id_;
178};
179
180} // namespace cricket
181
182#endif // PC_USED_IDS_H_