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