blob: 78e64caa4137ca364f4434ecff1ba259c3e007b5 [file] [log] [blame]
Johannes Kron746dd0d2019-06-20 15:37:52 +02001/*
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
31 // Loops through all Id in |ids| and changes its id if it is
32 // 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
42 // Finds and sets an unused id if the |idstruct| id is already in use.
43 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();
55 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
56 << original_id << " to " << new_id;
57 idstruct->id = new_id;
58 }
59 SetIdUsed(new_id);
60 }
61
62 protected:
63 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
64 const int min_allowed_id_;
65 const int max_allowed_id_;
66
67 private:
68 // Returns the first unused id in reverse order.
69 // This hopefully reduces the risk of more collisions. We want to change the
70 // default ids as little as possible. This function is virtual and can be
71 // overriden if the search for unused IDs should follow a specific pattern.
72 virtual int FindUnusedId() {
73 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
74 --next_id_;
75 }
76 RTC_DCHECK(next_id_ >= min_allowed_id_);
77 return next_id_;
78 }
79
80 void SetIdUsed(int new_id) {
81 RTC_DCHECK(new_id >= min_allowed_id_);
82 RTC_DCHECK(new_id <= max_allowed_id_);
83 RTC_DCHECK(!IsIdUsed(new_id));
84 id_set_.insert(new_id);
85 }
86 int next_id_;
87 std::set<int> id_set_;
88};
89
90// Helper class used for finding duplicate RTP payload types among audio, video
91// and data codecs. When bundle is used the payload types may not collide.
92class UsedPayloadTypes : public UsedIds<Codec> {
93 public:
94 UsedPayloadTypes()
95 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
96
97 private:
98 static const int kDynamicPayloadTypeMin = 96;
99 static const int kDynamicPayloadTypeMax = 127;
100};
101
102// Helper class used for finding duplicate RTP Header extension ids among
103// audio and video extensions.
104class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
105 public:
106 enum class IdDomain {
107 // Only allocate IDs that fit in one-byte header extensions.
108 kOneByteOnly,
109 // Prefer to allocate one-byte header extension IDs, but overflow to
110 // two-byte if none are left.
111 kTwoByteAllowed,
112 };
113
114 explicit UsedRtpHeaderExtensionIds(IdDomain id_domain)
115 : UsedIds<webrtc::RtpExtension>(
116 webrtc::RtpExtension::kMinId,
117 id_domain == IdDomain::kTwoByteAllowed
118 ? webrtc::RtpExtension::kMaxId
119 : webrtc::RtpExtension::kOneByteHeaderExtensionMaxId),
120 id_domain_(id_domain),
121 next_extension_id_(webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
122 }
123
124 private:
125 // Returns the first unused id in reverse order from the max id of one byte
126 // header extensions. This hopefully reduce the risk of more collisions. We
127 // want to change the default ids as little as possible. If no unused id is
128 // found and two byte header extensions are enabled (i.e.,
129 // |extmap_allow_mixed_| is true), search for unused ids from 15 to 255.
130 int FindUnusedId() override {
131 if (next_extension_id_ <=
132 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
133 // First search in reverse order from the max id of one byte header
134 // extensions.
135 while (IsIdUsed(next_extension_id_) &&
136 next_extension_id_ >= min_allowed_id_) {
137 --next_extension_id_;
138 }
139 }
140
141 if (id_domain_ == IdDomain::kTwoByteAllowed) {
142 if (next_extension_id_ < min_allowed_id_) {
143 // We have searched among all one-byte IDs without finding an unused ID,
144 // continue at the first two-byte ID.
145 next_extension_id_ =
146 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId + 1;
147 }
148
149 if (next_extension_id_ >
150 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
151 while (IsIdUsed(next_extension_id_) &&
152 next_extension_id_ <= max_allowed_id_) {
153 ++next_extension_id_;
154 }
155 }
156 }
157 RTC_DCHECK(next_extension_id_ >= min_allowed_id_);
158 RTC_DCHECK(next_extension_id_ <= max_allowed_id_);
159 return next_extension_id_;
160 }
161
162 const IdDomain id_domain_;
163 int next_extension_id_;
164};
165
166} // namespace cricket
167
168#endif // PC_USED_IDS_H_