used_ids.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  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. #include <set>
  13. #include <vector>
  14. #include "api/rtp_parameters.h"
  15. #include "media/base/codec.h"
  16. #include "rtc_base/checks.h"
  17. #include "rtc_base/logging.h"
  18. namespace cricket {
  19. template <typename IdStruct>
  20. class UsedIds {
  21. public:
  22. UsedIds(int min_allowed_id, int max_allowed_id)
  23. : min_allowed_id_(min_allowed_id),
  24. max_allowed_id_(max_allowed_id),
  25. next_id_(max_allowed_id) {}
  26. virtual ~UsedIds() {}
  27. // Loops through all Id in |ids| and changes its id if it is
  28. // already in use by another IdStruct. Call this methods with all Id
  29. // in a session description to make sure no duplicate ids exists.
  30. // Note that typename Id must be a type of IdStruct.
  31. template <typename Id>
  32. void FindAndSetIdUsed(std::vector<Id>* ids) {
  33. for (const Id& id : *ids) {
  34. FindAndSetIdUsed(&id);
  35. }
  36. }
  37. // Finds and sets an unused id if the |idstruct| id is already in use.
  38. void FindAndSetIdUsed(IdStruct* idstruct) {
  39. const int original_id = idstruct->id;
  40. int new_id = idstruct->id;
  41. if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
  42. // If the original id is not in range - this is an id that can't be
  43. // dynamically changed.
  44. return;
  45. }
  46. if (IsIdUsed(original_id)) {
  47. new_id = FindUnusedId();
  48. RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
  49. << original_id << " to " << new_id;
  50. idstruct->id = new_id;
  51. }
  52. SetIdUsed(new_id);
  53. }
  54. protected:
  55. bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
  56. const int min_allowed_id_;
  57. const int max_allowed_id_;
  58. private:
  59. // Returns the first unused id in reverse order.
  60. // This hopefully reduces the risk of more collisions. We want to change the
  61. // default ids as little as possible. This function is virtual and can be
  62. // overriden if the search for unused IDs should follow a specific pattern.
  63. virtual int FindUnusedId() {
  64. while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
  65. --next_id_;
  66. }
  67. RTC_DCHECK(next_id_ >= min_allowed_id_);
  68. return next_id_;
  69. }
  70. void SetIdUsed(int new_id) {
  71. RTC_DCHECK(new_id >= min_allowed_id_);
  72. RTC_DCHECK(new_id <= max_allowed_id_);
  73. RTC_DCHECK(!IsIdUsed(new_id));
  74. id_set_.insert(new_id);
  75. }
  76. int next_id_;
  77. std::set<int> id_set_;
  78. };
  79. // Helper class used for finding duplicate RTP payload types among audio, video
  80. // and data codecs. When bundle is used the payload types may not collide.
  81. class UsedPayloadTypes : public UsedIds<Codec> {
  82. public:
  83. UsedPayloadTypes()
  84. : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
  85. private:
  86. static const int kDynamicPayloadTypeMin = 96;
  87. static const int kDynamicPayloadTypeMax = 127;
  88. };
  89. // Helper class used for finding duplicate RTP Header extension ids among
  90. // audio and video extensions.
  91. class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
  92. public:
  93. enum class IdDomain {
  94. // Only allocate IDs that fit in one-byte header extensions.
  95. kOneByteOnly,
  96. // Prefer to allocate one-byte header extension IDs, but overflow to
  97. // two-byte if none are left.
  98. kTwoByteAllowed,
  99. };
  100. explicit UsedRtpHeaderExtensionIds(IdDomain id_domain)
  101. : UsedIds<webrtc::RtpExtension>(
  102. webrtc::RtpExtension::kMinId,
  103. id_domain == IdDomain::kTwoByteAllowed
  104. ? webrtc::RtpExtension::kMaxId
  105. : webrtc::RtpExtension::kOneByteHeaderExtensionMaxId),
  106. id_domain_(id_domain),
  107. next_extension_id_(webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
  108. }
  109. private:
  110. // Returns the first unused id in reverse order from the max id of one byte
  111. // header extensions. This hopefully reduce the risk of more collisions. We
  112. // want to change the default ids as little as possible. If no unused id is
  113. // found and two byte header extensions are enabled (i.e.,
  114. // |extmap_allow_mixed_| is true), search for unused ids from 15 to 255.
  115. int FindUnusedId() override {
  116. if (next_extension_id_ <=
  117. webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
  118. // First search in reverse order from the max id of one byte header
  119. // extensions.
  120. while (IsIdUsed(next_extension_id_) &&
  121. next_extension_id_ >= min_allowed_id_) {
  122. --next_extension_id_;
  123. }
  124. }
  125. if (id_domain_ == IdDomain::kTwoByteAllowed) {
  126. if (next_extension_id_ < min_allowed_id_) {
  127. // We have searched among all one-byte IDs without finding an unused ID,
  128. // continue at the first two-byte ID.
  129. next_extension_id_ =
  130. webrtc::RtpExtension::kOneByteHeaderExtensionMaxId + 1;
  131. }
  132. if (next_extension_id_ >
  133. webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
  134. while (IsIdUsed(next_extension_id_) &&
  135. next_extension_id_ <= max_allowed_id_) {
  136. ++next_extension_id_;
  137. }
  138. }
  139. }
  140. RTC_DCHECK(next_extension_id_ >= min_allowed_id_);
  141. RTC_DCHECK(next_extension_id_ <= max_allowed_id_);
  142. return next_extension_id_;
  143. }
  144. const IdDomain id_domain_;
  145. int next_extension_id_;
  146. };
  147. } // namespace cricket
  148. #endif // PC_USED_IDS_H_