mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
6a8c313b74
Upstream commit: https://webrtc.googlesource.com/src/+/cea1c0b9a91be940ec801ab84a7ca3b52e9fc930 Dynamically assign ids to header extensions not enabled by default by creating an id collision and letting UsedIds resolve it. Also avoid id=15 which is forbidden by https://www.rfc-editor.org/rfc/rfc8285#section-4.2 so might cause interop issues in offers to implementations not supporting two-byte extensions. BUG=webrtc:15378 Change-Id: I27926f065f8e396257294da7acf2be9802169805 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/319280 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Commit-Queue: Philipp Hancke <phancke@microsoft.com> Cr-Commit-Position: refs/heads/main@{#41696}
194 lines
6.4 KiB
C++
194 lines
6.4 KiB
C++
/*
|
|
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
#ifndef PC_USED_IDS_H_
|
|
#define PC_USED_IDS_H_
|
|
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include "api/rtp_parameters.h"
|
|
#include "media/base/codec.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace cricket {
|
|
template <typename IdStruct>
|
|
class UsedIds {
|
|
public:
|
|
UsedIds(int min_allowed_id, int max_allowed_id)
|
|
: min_allowed_id_(min_allowed_id),
|
|
max_allowed_id_(max_allowed_id),
|
|
next_id_(max_allowed_id) {}
|
|
virtual ~UsedIds() {}
|
|
|
|
// Loops through all Id in `ids` and changes its id if it is
|
|
// already in use by another IdStruct. Call this methods with all Id
|
|
// in a session description to make sure no duplicate ids exists.
|
|
// Note that typename Id must be a type of IdStruct.
|
|
template <typename Id>
|
|
void FindAndSetIdUsed(std::vector<Id>* ids) {
|
|
for (const Id& id : *ids) {
|
|
FindAndSetIdUsed(&id);
|
|
}
|
|
}
|
|
|
|
// Finds and sets an unused id if the `idstruct` id is already in use.
|
|
void FindAndSetIdUsed(IdStruct* idstruct) {
|
|
const int original_id = idstruct->id;
|
|
int new_id = idstruct->id;
|
|
|
|
if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
|
|
// If the original id is not in range - this is an id that can't be
|
|
// dynamically changed.
|
|
return;
|
|
}
|
|
|
|
if (IsIdUsed(original_id)) {
|
|
new_id = FindUnusedId();
|
|
// Duplicate id found. Reassign from the original id to the new.
|
|
idstruct->id = new_id;
|
|
}
|
|
SetIdUsed(new_id);
|
|
}
|
|
|
|
protected:
|
|
virtual bool IsIdUsed(int new_id) {
|
|
return id_set_.find(new_id) != id_set_.end();
|
|
}
|
|
const int min_allowed_id_;
|
|
const int max_allowed_id_;
|
|
|
|
private:
|
|
// Returns the first unused id in reverse order.
|
|
// This hopefully reduces the risk of more collisions. We want to change the
|
|
// default ids as little as possible. This function is virtual and can be
|
|
// overriden if the search for unused IDs should follow a specific pattern.
|
|
virtual int FindUnusedId() {
|
|
while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
|
|
--next_id_;
|
|
}
|
|
RTC_DCHECK(next_id_ >= min_allowed_id_);
|
|
return next_id_;
|
|
}
|
|
|
|
void SetIdUsed(int new_id) {
|
|
RTC_DCHECK(new_id >= min_allowed_id_);
|
|
RTC_DCHECK(new_id <= max_allowed_id_);
|
|
RTC_DCHECK(!IsIdUsed(new_id));
|
|
id_set_.insert(new_id);
|
|
}
|
|
int next_id_;
|
|
std::set<int> id_set_;
|
|
};
|
|
|
|
// Helper class used for finding duplicate RTP payload types among audio, video
|
|
// and data codecs. When bundle is used the payload types may not collide.
|
|
class UsedPayloadTypes : public UsedIds<Codec> {
|
|
public:
|
|
UsedPayloadTypes()
|
|
: UsedIds<Codec>(kFirstDynamicPayloadTypeLowerRange,
|
|
kLastDynamicPayloadTypeUpperRange) {}
|
|
|
|
// Check if a payload type is valid. The range [64-95] is forbidden
|
|
// when rtcp-mux is used.
|
|
static bool IsIdValid(Codec codec, bool rtcp_mux) {
|
|
if (rtcp_mux && (codec.id > kLastDynamicPayloadTypeLowerRange &&
|
|
codec.id < kFirstDynamicPayloadTypeUpperRange)) {
|
|
return false;
|
|
}
|
|
return codec.id >= 0 && codec.id <= kLastDynamicPayloadTypeUpperRange;
|
|
}
|
|
|
|
protected:
|
|
bool IsIdUsed(int new_id) override {
|
|
// Range marked for RTCP avoidance is "used".
|
|
if (new_id > kLastDynamicPayloadTypeLowerRange &&
|
|
new_id < kFirstDynamicPayloadTypeUpperRange)
|
|
return true;
|
|
return UsedIds<Codec>::IsIdUsed(new_id);
|
|
}
|
|
|
|
private:
|
|
static const int kFirstDynamicPayloadTypeLowerRange = 35;
|
|
static const int kLastDynamicPayloadTypeLowerRange = 63;
|
|
|
|
static const int kFirstDynamicPayloadTypeUpperRange = 96;
|
|
static const int kLastDynamicPayloadTypeUpperRange = 127;
|
|
};
|
|
|
|
// Helper class used for finding duplicate RTP Header extension ids among
|
|
// audio and video extensions.
|
|
class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
|
|
public:
|
|
enum class IdDomain {
|
|
// Only allocate IDs that fit in one-byte header extensions.
|
|
kOneByteOnly,
|
|
// Prefer to allocate one-byte header extension IDs, but overflow to
|
|
// two-byte if none are left.
|
|
kTwoByteAllowed,
|
|
};
|
|
|
|
explicit UsedRtpHeaderExtensionIds(IdDomain id_domain)
|
|
: UsedIds<webrtc::RtpExtension>(
|
|
webrtc::RtpExtension::kMinId,
|
|
id_domain == IdDomain::kTwoByteAllowed
|
|
? webrtc::RtpExtension::kMaxId
|
|
: webrtc::RtpExtension::kOneByteHeaderExtensionMaxId),
|
|
id_domain_(id_domain),
|
|
next_extension_id_(webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
|
|
}
|
|
|
|
private:
|
|
// Returns the first unused id in reverse order from the max id of one byte
|
|
// header extensions. This hopefully reduces the risk of more collisions. We
|
|
// want to change the default ids as little as possible. If no unused id is
|
|
// found and two byte header extensions are enabled (i.e.,
|
|
// `extmap_allow_mixed_` is true), search for unused ids from 16 to 255.
|
|
int FindUnusedId() override {
|
|
if (next_extension_id_ <=
|
|
webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
|
|
// First search in reverse order from the max id of one byte header
|
|
// extensions (14).
|
|
while (IsIdUsed(next_extension_id_) &&
|
|
next_extension_id_ >= min_allowed_id_) {
|
|
--next_extension_id_;
|
|
}
|
|
}
|
|
|
|
if (id_domain_ == IdDomain::kTwoByteAllowed) {
|
|
if (next_extension_id_ < min_allowed_id_) {
|
|
// We have searched among all one-byte IDs without finding an unused ID,
|
|
// continue at the first two-byte ID (16; avoid 15 since it is somewhat
|
|
// special per https://www.rfc-editor.org/rfc/rfc8285#section-4.2
|
|
next_extension_id_ =
|
|
webrtc::RtpExtension::kOneByteHeaderExtensionMaxId + 2;
|
|
}
|
|
|
|
if (next_extension_id_ >
|
|
webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {
|
|
while (IsIdUsed(next_extension_id_) &&
|
|
next_extension_id_ <= max_allowed_id_) {
|
|
++next_extension_id_;
|
|
}
|
|
}
|
|
}
|
|
RTC_DCHECK(next_extension_id_ >= min_allowed_id_);
|
|
RTC_DCHECK(next_extension_id_ <= max_allowed_id_);
|
|
return next_extension_id_;
|
|
}
|
|
|
|
const IdDomain id_domain_;
|
|
int next_extension_id_;
|
|
};
|
|
|
|
} // namespace cricket
|
|
|
|
#endif // PC_USED_IDS_H_
|