| /* | 
 |  *  Copyright (c) 2017 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. | 
 |  */ | 
 | #include "api/rtp_parameters.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <cstdint> | 
 | #include <string> | 
 | #include <tuple> | 
 | #include <vector> | 
 |  | 
 | #include "absl/strings/string_view.h" | 
 | #include "api/array_view.h" | 
 | #include "api/rtp_transceiver_direction.h" | 
 | #include "media/base/media_constants.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/strings/string_builder.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | const char* DegradationPreferenceToString( | 
 |     DegradationPreference degradation_preference) { | 
 |   switch (degradation_preference) { | 
 |     case DegradationPreference::DISABLED: | 
 |       return "disabled"; | 
 |     case DegradationPreference::MAINTAIN_FRAMERATE: | 
 |       return "maintain-framerate"; | 
 |     case DegradationPreference::MAINTAIN_RESOLUTION: | 
 |       return "maintain-resolution"; | 
 |     case DegradationPreference::BALANCED: | 
 |       return "balanced"; | 
 |   } | 
 |   RTC_CHECK_NOTREACHED(); | 
 | } | 
 |  | 
 | const double kDefaultBitratePriority = 1.0; | 
 |  | 
 | RtcpFeedback::RtcpFeedback() = default; | 
 | RtcpFeedback::RtcpFeedback(RtcpFeedbackType type) : type(type) {} | 
 | RtcpFeedback::RtcpFeedback(RtcpFeedbackType type, | 
 |                            RtcpFeedbackMessageType message_type) | 
 |     : type(type), message_type(message_type) {} | 
 | RtcpFeedback::RtcpFeedback(const RtcpFeedback& rhs) = default; | 
 | RtcpFeedback::~RtcpFeedback() = default; | 
 |  | 
 | RtpCodec::RtpCodec() = default; | 
 | RtpCodec::RtpCodec(const RtpCodec&) = default; | 
 | RtpCodec::~RtpCodec() = default; | 
 | bool RtpCodec::IsResiliencyCodec() const { | 
 |   return name == cricket::kRtxCodecName || name == cricket::kRedCodecName || | 
 |          name == cricket::kUlpfecCodecName || | 
 |          name == cricket::kFlexfecCodecName; | 
 | } | 
 | bool RtpCodec::IsMediaCodec() const { | 
 |   return !IsResiliencyCodec() && name != cricket::kComfortNoiseCodecName; | 
 | } | 
 | RtpCodecCapability::RtpCodecCapability() = default; | 
 | RtpCodecCapability::~RtpCodecCapability() = default; | 
 |  | 
 | RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() = default; | 
 | RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( | 
 |     absl::string_view uri) | 
 |     : uri(uri) {} | 
 | RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( | 
 |     absl::string_view uri, | 
 |     int preferred_id) | 
 |     : uri(uri), preferred_id(preferred_id) {} | 
 | RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( | 
 |     absl::string_view uri, | 
 |     int preferred_id, | 
 |     RtpTransceiverDirection direction) | 
 |     : uri(uri), preferred_id(preferred_id), direction(direction) {} | 
 | RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( | 
 |     absl::string_view uri, | 
 |     int preferred_id, | 
 |     bool preferred_encrypt, | 
 |     RtpTransceiverDirection direction) | 
 |     : uri(uri), | 
 |       preferred_id(preferred_id), | 
 |       preferred_encrypt(preferred_encrypt), | 
 |       direction(direction) {} | 
 | RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default; | 
 |  | 
 | RtpExtension::RtpExtension() = default; | 
 | RtpExtension::RtpExtension(absl::string_view uri, int id) : uri(uri), id(id) {} | 
 | RtpExtension::RtpExtension(absl::string_view uri, int id, bool encrypt) | 
 |     : uri(uri), id(id), encrypt(encrypt) {} | 
 | RtpExtension::~RtpExtension() = default; | 
 |  | 
 | RtpFecParameters::RtpFecParameters() = default; | 
 | RtpFecParameters::RtpFecParameters(FecMechanism mechanism) | 
 |     : mechanism(mechanism) {} | 
 | RtpFecParameters::RtpFecParameters(FecMechanism mechanism, uint32_t ssrc) | 
 |     : ssrc(ssrc), mechanism(mechanism) {} | 
 | RtpFecParameters::RtpFecParameters(const RtpFecParameters& rhs) = default; | 
 | RtpFecParameters::~RtpFecParameters() = default; | 
 |  | 
 | RtpRtxParameters::RtpRtxParameters() = default; | 
 | RtpRtxParameters::RtpRtxParameters(uint32_t ssrc) : ssrc(ssrc) {} | 
 | RtpRtxParameters::RtpRtxParameters(const RtpRtxParameters& rhs) = default; | 
 | RtpRtxParameters::~RtpRtxParameters() = default; | 
 |  | 
 | RtpEncodingParameters::RtpEncodingParameters() = default; | 
 | RtpEncodingParameters::RtpEncodingParameters(const RtpEncodingParameters& rhs) = | 
 |     default; | 
 | RtpEncodingParameters::~RtpEncodingParameters() = default; | 
 |  | 
 | RtpCodecParameters::RtpCodecParameters() = default; | 
 | RtpCodecParameters::RtpCodecParameters(const RtpCodecParameters& rhs) = default; | 
 | RtpCodecParameters::~RtpCodecParameters() = default; | 
 |  | 
 | RtpCapabilities::RtpCapabilities() = default; | 
 | RtpCapabilities::~RtpCapabilities() = default; | 
 |  | 
 | RtcpParameters::RtcpParameters() = default; | 
 | RtcpParameters::RtcpParameters(const RtcpParameters& rhs) = default; | 
 | RtcpParameters::~RtcpParameters() = default; | 
 |  | 
 | RtpParameters::RtpParameters() = default; | 
 | RtpParameters::RtpParameters(const RtpParameters& rhs) = default; | 
 | RtpParameters::~RtpParameters() = default; | 
 |  | 
 | std::string RtpExtension::ToString() const { | 
 |   char buf[256]; | 
 |   SimpleStringBuilder sb(buf); | 
 |   sb << "{uri: " << uri; | 
 |   sb << ", id: " << id; | 
 |   if (encrypt) { | 
 |     sb << ", encrypt"; | 
 |   } | 
 |   sb << '}'; | 
 |   return sb.str(); | 
 | } | 
 |  | 
 | constexpr char RtpExtension::kEncryptHeaderExtensionsUri[]; | 
 | constexpr char RtpExtension::kAudioLevelUri[]; | 
 | constexpr char RtpExtension::kTimestampOffsetUri[]; | 
 | constexpr char RtpExtension::kAbsSendTimeUri[]; | 
 | constexpr char RtpExtension::kAbsoluteCaptureTimeUri[]; | 
 | constexpr char RtpExtension::kVideoRotationUri[]; | 
 | constexpr char RtpExtension::kVideoContentTypeUri[]; | 
 | constexpr char RtpExtension::kVideoTimingUri[]; | 
 | constexpr char RtpExtension::kGenericFrameDescriptorUri00[]; | 
 | constexpr char RtpExtension::kDependencyDescriptorUri[]; | 
 | constexpr char RtpExtension::kVideoLayersAllocationUri[]; | 
 | constexpr char RtpExtension::kTransportSequenceNumberUri[]; | 
 | constexpr char RtpExtension::kTransportSequenceNumberV2Uri[]; | 
 | constexpr char RtpExtension::kPlayoutDelayUri[]; | 
 | constexpr char RtpExtension::kColorSpaceUri[]; | 
 | constexpr char RtpExtension::kMidUri[]; | 
 | constexpr char RtpExtension::kRidUri[]; | 
 | constexpr char RtpExtension::kRepairedRidUri[]; | 
 | constexpr char RtpExtension::kVideoFrameTrackingIdUri[]; | 
 | constexpr char RtpExtension::kCsrcAudioLevelsUri[]; | 
 | constexpr char RtpExtension::kCorruptionDetectionUri[]; | 
 |  | 
 | constexpr int RtpExtension::kMinId; | 
 | constexpr int RtpExtension::kMaxId; | 
 | constexpr int RtpExtension::kMaxValueSize; | 
 | constexpr int RtpExtension::kOneByteHeaderExtensionMaxId; | 
 | constexpr int RtpExtension::kOneByteHeaderExtensionMaxValueSize; | 
 |  | 
 | bool RtpExtension::IsSupportedForAudio(absl::string_view uri) { | 
 |   return uri == webrtc::RtpExtension::kAudioLevelUri || | 
 |          uri == webrtc::RtpExtension::kAbsSendTimeUri || | 
 |          uri == webrtc::RtpExtension::kAbsoluteCaptureTimeUri || | 
 |          uri == webrtc::RtpExtension::kTransportSequenceNumberUri || | 
 |          uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || | 
 |          uri == webrtc::RtpExtension::kMidUri || | 
 |          uri == webrtc::RtpExtension::kRidUri || | 
 |          uri == webrtc::RtpExtension::kRepairedRidUri; | 
 | } | 
 |  | 
 | bool RtpExtension::IsSupportedForVideo(absl::string_view uri) { | 
 |   return uri == webrtc::RtpExtension::kTimestampOffsetUri || | 
 |          uri == webrtc::RtpExtension::kAbsSendTimeUri || | 
 |          uri == webrtc::RtpExtension::kAbsoluteCaptureTimeUri || | 
 |          uri == webrtc::RtpExtension::kVideoRotationUri || | 
 |          uri == webrtc::RtpExtension::kTransportSequenceNumberUri || | 
 |          uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || | 
 |          uri == webrtc::RtpExtension::kPlayoutDelayUri || | 
 |          uri == webrtc::RtpExtension::kVideoContentTypeUri || | 
 |          uri == webrtc::RtpExtension::kVideoTimingUri || | 
 |          uri == webrtc::RtpExtension::kMidUri || | 
 |          uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00 || | 
 |          uri == webrtc::RtpExtension::kDependencyDescriptorUri || | 
 |          uri == webrtc::RtpExtension::kColorSpaceUri || | 
 |          uri == webrtc::RtpExtension::kRidUri || | 
 |          uri == webrtc::RtpExtension::kRepairedRidUri || | 
 |          uri == webrtc::RtpExtension::kVideoLayersAllocationUri || | 
 |          uri == webrtc::RtpExtension::kVideoFrameTrackingIdUri || | 
 |          uri == webrtc::RtpExtension::kCorruptionDetectionUri; | 
 | } | 
 |  | 
 | bool RtpExtension::IsEncryptionSupported(absl::string_view uri) { | 
 |   return | 
 | #if defined(ENABLE_EXTERNAL_AUTH) | 
 |       // TODO(jbauch): Figure out a way to always allow "kAbsSendTimeUri" | 
 |       // here and filter out later if external auth is really used in | 
 |       // srtpfilter. External auth is used by Chromium and replaces the | 
 |       // extension header value of "kAbsSendTimeUri", so it must not be | 
 |       // encrypted (which can't be done by Chromium). | 
 |       uri != webrtc::RtpExtension::kAbsSendTimeUri && | 
 | #endif | 
 |       uri != webrtc::RtpExtension::kEncryptHeaderExtensionsUri; | 
 | } | 
 |  | 
 | // Returns whether a header extension with the given URI exists. | 
 | // Note: This does not differentiate between encrypted and non-encrypted | 
 | // extensions, so use with care! | 
 | static bool HeaderExtensionWithUriExists( | 
 |     const std::vector<RtpExtension>& extensions, | 
 |     absl::string_view uri) { | 
 |   for (const auto& extension : extensions) { | 
 |     if (extension.uri == uri) { | 
 |       return true; | 
 |     } | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | const RtpExtension* RtpExtension::FindHeaderExtensionByUri( | 
 |     const std::vector<RtpExtension>& extensions, | 
 |     absl::string_view uri, | 
 |     Filter filter) { | 
 |   const webrtc::RtpExtension* fallback_extension = nullptr; | 
 |   for (const auto& extension : extensions) { | 
 |     if (extension.uri != uri) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     switch (filter) { | 
 |       case kDiscardEncryptedExtension: | 
 |         // We only accept an unencrypted extension. | 
 |         if (!extension.encrypt) { | 
 |           return &extension; | 
 |         } | 
 |         break; | 
 |  | 
 |       case kPreferEncryptedExtension: | 
 |         // We prefer an encrypted extension but we can fall back to an | 
 |         // unencrypted extension. | 
 |         if (extension.encrypt) { | 
 |           return &extension; | 
 |         } else { | 
 |           fallback_extension = &extension; | 
 |         } | 
 |         break; | 
 |  | 
 |       case kRequireEncryptedExtension: | 
 |         // We only accept an encrypted extension. | 
 |         if (extension.encrypt) { | 
 |           return &extension; | 
 |         } | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   // Returning fallback extension (if any) | 
 |   return fallback_extension; | 
 | } | 
 |  | 
 | const RtpExtension* RtpExtension::FindHeaderExtensionByUriAndEncryption( | 
 |     const std::vector<RtpExtension>& extensions, | 
 |     absl::string_view uri, | 
 |     bool encrypt) { | 
 |   for (const auto& extension : extensions) { | 
 |     if (extension.uri == uri && extension.encrypt == encrypt) { | 
 |       return &extension; | 
 |     } | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | const std::vector<RtpExtension> RtpExtension::DeduplicateHeaderExtensions( | 
 |     const std::vector<RtpExtension>& extensions, | 
 |     Filter filter) { | 
 |   std::vector<RtpExtension> filtered; | 
 |  | 
 |   // If we do not discard encrypted extensions, add them first | 
 |   if (filter != kDiscardEncryptedExtension) { | 
 |     for (const auto& extension : extensions) { | 
 |       if (!extension.encrypt) { | 
 |         continue; | 
 |       } | 
 |       if (!HeaderExtensionWithUriExists(filtered, extension.uri)) { | 
 |         filtered.push_back(extension); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // If we do not require encrypted extensions, add missing, non-encrypted | 
 |   // extensions. | 
 |   if (filter != kRequireEncryptedExtension) { | 
 |     for (const auto& extension : extensions) { | 
 |       if (extension.encrypt) { | 
 |         continue; | 
 |       } | 
 |       if (!HeaderExtensionWithUriExists(filtered, extension.uri)) { | 
 |         filtered.push_back(extension); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Sort the returned vector to make comparisons of header extensions reliable. | 
 |   // In order of priority, we sort by uri first, then encrypt and id last. | 
 |   std::sort(filtered.begin(), filtered.end(), | 
 |             [](const RtpExtension& a, const RtpExtension& b) { | 
 |               return std::tie(a.uri, a.encrypt, a.id) < | 
 |                      std::tie(b.uri, b.encrypt, b.id); | 
 |             }); | 
 |  | 
 |   return filtered; | 
 | } | 
 | }  // namespace webrtc |