Thanks to visit codestin.com
Credit goes to webrtc.googlesource.com

blob: 7ca5481bca89e78b72c3588b3be5349545d0d7aa [file] [log] [blame]
Stefan Holmer1acbd682017-09-01 13:29:281/*
2 * Copyright (c) 2017 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 */
Steve Anton10542f22019-01-11 17:11:0010#include "api/rtp_parameters.h"
Stefan Holmer1acbd682017-09-01 13:29:2811
12#include <algorithm>
Dor Henaefed552024-06-18 13:20:3513#include <cstdint>
Shigemasa Watanabe63c20e92025-10-18 10:18:5314#include <optional>
Stefan Holmer1acbd682017-09-01 13:29:2815#include <string>
Tomas Gunnarssonc69453d2022-01-06 12:36:0416#include <tuple>
Dor Henaefed552024-06-18 13:20:3517#include <vector>
Stefan Holmer1acbd682017-09-01 13:29:2818
Tommi932f2742025-10-10 14:04:3219#include "absl/strings/ascii.h"
Dor Henaefed552024-06-18 13:20:3520#include "absl/strings/string_view.h"
Yves Gerey988cc082018-10-23 10:03:0121#include "api/array_view.h"
Tommi932f2742025-10-10 14:04:3222#include "api/rtc_error.h"
Dor Henaefed552024-06-18 13:20:3523#include "api/rtp_transceiver_direction.h"
Philipp Hanckeb9405c42023-12-07 17:00:4724#include "media/base/media_constants.h"
Dor Henaefed552024-06-18 13:20:3525#include "rtc_base/checks.h"
Tommi932f2742025-10-10 14:04:3226#include "rtc_base/logging.h"
27#include "rtc_base/string_encode.h"
Jonas Olsson866d6dc2018-05-14 15:30:2228#include "rtc_base/strings/string_builder.h"
Stefan Holmer1acbd682017-09-01 13:29:2829
30namespace webrtc {
Tommi932f2742025-10-10 14:04:3231namespace {
32constexpr char kSdpDelimiterSemicolon[] = ";";
33constexpr char kSdpDelimiterEqualChar = '=';
34constexpr char kSdpDelimiterEqual[] = "=";
35constexpr char kSdpDelimiterSemicolonChar = ';';
36
37void ParseFmtpParam(absl::string_view line,
38 std::string* parameter,
39 std::string* value) {
40 if (!tokenize_first(line, kSdpDelimiterEqualChar, parameter, value)) {
41 // Support for non-key-value lines like RFC 2198 or RFC 4733.
42 *parameter = "";
43 *value = std::string(line);
44 }
45 // a=fmtp:<payload_type> <param1>=<value1>; <param2>=<value2>; ...
46}
47
48bool IsFmtpParam(absl::string_view name) {
49 // RFC 4855, section 3 specifies the mapping of media format parameters to SDP
50 // parameters. Only ptime, maxptime, channels and rate are placed outside of
51 // the fmtp line. In WebRTC, channels and rate are already handled separately
52 // and thus not included in the CodecParameterMap.
53 return name != kCodecParamPTime && name != kCodecParamMaxPTime;
54}
55
56void WriteFmtpParameter(absl::string_view parameter_name,
57 absl::string_view parameter_value,
58 StringBuilder& os) {
59 if (parameter_name.empty()) {
60 // RFC 2198 and RFC 4733 don't use key-value pairs.
61 os << parameter_value;
62 } else {
63 // fmtp parameters: `parameter_name`=`parameter_value`
64 os << parameter_name << kSdpDelimiterEqual << parameter_value;
65 }
66}
67
68} // namespace
Stefan Holmer1acbd682017-09-01 13:29:2869
Henrik Boströmf0eef122020-05-28 14:22:4270const char* DegradationPreferenceToString(
71 DegradationPreference degradation_preference) {
72 switch (degradation_preference) {
Sergey Silkin95593092025-10-10 11:14:0073 case DegradationPreference::MAINTAIN_FRAMERATE_AND_RESOLUTION:
74 return "maintain-framerate-and-resolution";
Henrik Boströmf0eef122020-05-28 14:22:4275 case DegradationPreference::MAINTAIN_FRAMERATE:
76 return "maintain-framerate";
77 case DegradationPreference::MAINTAIN_RESOLUTION:
78 return "maintain-resolution";
79 case DegradationPreference::BALANCED:
80 return "balanced";
81 }
Karl Wibergc95b9392020-11-07 23:49:3782 RTC_CHECK_NOTREACHED();
Henrik Boströmf0eef122020-05-28 14:22:4283}
84
Seth Hampsonf32795e2017-12-19 19:37:4185const double kDefaultBitratePriority = 1.0;
86
Tommi932f2742025-10-10 14:04:3287bool WriteFmtpParameters(const CodecParameterMap& parameters,
88 StringBuilder& os) {
89 bool empty = true;
90 const char* delimiter = ""; // No delimiter before first parameter.
91 for (const auto& entry : parameters) {
92 const std::string& key = entry.first;
93 const std::string& value = entry.second;
94
95 if (IsFmtpParam(key)) {
96 os << delimiter;
97 // A semicolon before each subsequent parameter.
98 delimiter = kSdpDelimiterSemicolon;
99 WriteFmtpParameter(key, value, os);
100 empty = false;
101 }
102 }
103
104 return !empty;
105}
106
107RTCError ParseFmtpParameterSet(absl::string_view line_params,
108 CodecParameterMap& codec_params) {
109 // Parse out format specific parameters.
110 for (absl::string_view param :
111 split(line_params, kSdpDelimiterSemicolonChar)) {
112 std::string name;
113 std::string value;
114 ParseFmtpParam(absl::StripAsciiWhitespace(param), &name, &value);
115 if (codec_params.find(name) != codec_params.end()) {
116 RTC_LOG(LS_INFO) << "Overwriting duplicate fmtp parameter with key \""
117 << name << "\".";
118 }
119 codec_params[name] = value;
120 }
121 return RTCError::OK();
122}
123
Mirko Bonadei2ffed6d2018-07-20 09:09:32124RtcpFeedback::RtcpFeedback() = default;
Stefan Holmer1acbd682017-09-01 13:29:28125RtcpFeedback::RtcpFeedback(RtcpFeedbackType type) : type(type) {}
126RtcpFeedback::RtcpFeedback(RtcpFeedbackType type,
127 RtcpFeedbackMessageType message_type)
128 : type(type), message_type(message_type) {}
Mirko Bonadei2ffed6d2018-07-20 09:09:32129RtcpFeedback::RtcpFeedback(const RtcpFeedback& rhs) = default;
130RtcpFeedback::~RtcpFeedback() = default;
Stefan Holmer1acbd682017-09-01 13:29:28131
Florent Castelli0a4a9842023-04-03 17:25:29132RtpCodec::RtpCodec() = default;
133RtpCodec::RtpCodec(const RtpCodec&) = default;
134RtpCodec::~RtpCodec() = default;
Philipp Hanckeb9405c42023-12-07 17:00:47135bool RtpCodec::IsResiliencyCodec() const {
Evan Shrubsole945e5172025-04-08 14:11:45136 return name == kRtxCodecName || name == kRedCodecName ||
137 name == kUlpfecCodecName || name == kFlexfecCodecName;
Philipp Hanckeb9405c42023-12-07 17:00:47138}
139bool RtpCodec::IsMediaCodec() const {
Evan Shrubsole945e5172025-04-08 14:11:45140 return !IsResiliencyCodec() && name != kComfortNoiseCodecName;
Philipp Hanckeb9405c42023-12-07 17:00:47141}
Mirko Bonadei2ffed6d2018-07-20 09:09:32142RtpCodecCapability::RtpCodecCapability() = default;
143RtpCodecCapability::~RtpCodecCapability() = default;
Stefan Holmer1acbd682017-09-01 13:29:28144
Mirko Bonadei2ffed6d2018-07-20 09:09:32145RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() = default;
Stefan Holmer1acbd682017-09-01 13:29:28146RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
Danil Chapovalov2b4ec9e2020-03-25 16:23:37147 absl::string_view uri)
148 : uri(uri) {}
149RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
150 absl::string_view uri,
151 int preferred_id)
152 : uri(uri), preferred_id(preferred_id) {}
153RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
154 absl::string_view uri,
Markus Handell0357b3e2020-03-16 12:40:51155 int preferred_id,
156 RtpTransceiverDirection direction)
Danil Chapovalov2b4ec9e2020-03-25 16:23:37157 : uri(uri), preferred_id(preferred_id), direction(direction) {}
Emil Vardarf5a547a2024-09-26 11:06:07158RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
159 absl::string_view uri,
160 int preferred_id,
161 bool preferred_encrypt,
162 RtpTransceiverDirection direction)
163 : uri(uri),
164 preferred_id(preferred_id),
165 preferred_encrypt(preferred_encrypt),
166 direction(direction) {}
Mirko Bonadei2ffed6d2018-07-20 09:09:32167RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default;
Stefan Holmer1acbd682017-09-01 13:29:28168
Mirko Bonadei2ffed6d2018-07-20 09:09:32169RtpExtension::RtpExtension() = default;
Danil Chapovalov2b4ec9e2020-03-25 16:23:37170RtpExtension::RtpExtension(absl::string_view uri, int id) : uri(uri), id(id) {}
171RtpExtension::RtpExtension(absl::string_view uri, int id, bool encrypt)
172 : uri(uri), id(id), encrypt(encrypt) {}
Mirko Bonadei2ffed6d2018-07-20 09:09:32173RtpExtension::~RtpExtension() = default;
Stefan Holmer1acbd682017-09-01 13:29:28174
Mirko Bonadei2ffed6d2018-07-20 09:09:32175RtpFecParameters::RtpFecParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28176RtpFecParameters::RtpFecParameters(FecMechanism mechanism)
177 : mechanism(mechanism) {}
178RtpFecParameters::RtpFecParameters(FecMechanism mechanism, uint32_t ssrc)
179 : ssrc(ssrc), mechanism(mechanism) {}
Mirko Bonadei2ffed6d2018-07-20 09:09:32180RtpFecParameters::RtpFecParameters(const RtpFecParameters& rhs) = default;
181RtpFecParameters::~RtpFecParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28182
Mirko Bonadei2ffed6d2018-07-20 09:09:32183RtpRtxParameters::RtpRtxParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28184RtpRtxParameters::RtpRtxParameters(uint32_t ssrc) : ssrc(ssrc) {}
Mirko Bonadei2ffed6d2018-07-20 09:09:32185RtpRtxParameters::RtpRtxParameters(const RtpRtxParameters& rhs) = default;
186RtpRtxParameters::~RtpRtxParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28187
Henrik Boström440ef022024-10-24 08:40:58188RtpEncodingParameters::RtpEncodingParameters() = default;
189RtpEncodingParameters::RtpEncodingParameters(const RtpEncodingParameters& rhs) =
190 default;
Mirko Bonadei2ffed6d2018-07-20 09:09:32191RtpEncodingParameters::~RtpEncodingParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28192
Mirko Bonadei2ffed6d2018-07-20 09:09:32193RtpCodecParameters::RtpCodecParameters() = default;
194RtpCodecParameters::RtpCodecParameters(const RtpCodecParameters& rhs) = default;
195RtpCodecParameters::~RtpCodecParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28196
Mirko Bonadei2ffed6d2018-07-20 09:09:32197RtpCapabilities::RtpCapabilities() = default;
198RtpCapabilities::~RtpCapabilities() = default;
Stefan Holmer1acbd682017-09-01 13:29:28199
Mirko Bonadei2ffed6d2018-07-20 09:09:32200RtcpParameters::RtcpParameters() = default;
201RtcpParameters::RtcpParameters(const RtcpParameters& rhs) = default;
202RtcpParameters::~RtcpParameters() = default;
Florent Castellidacec712018-05-24 14:24:21203
Mirko Bonadei2ffed6d2018-07-20 09:09:32204RtpParameters::RtpParameters() = default;
205RtpParameters::RtpParameters(const RtpParameters& rhs) = default;
206RtpParameters::~RtpParameters() = default;
Stefan Holmer1acbd682017-09-01 13:29:28207
208std::string RtpExtension::ToString() const {
Jonas Olsson866d6dc2018-05-14 15:30:22209 char buf[256];
Evan Shrubsole0ebd67f2025-02-19 10:06:32210 SimpleStringBuilder sb(buf);
Jonas Olsson866d6dc2018-05-14 15:30:22211 sb << "{uri: " << uri;
212 sb << ", id: " << id;
Stefan Holmer1acbd682017-09-01 13:29:28213 if (encrypt) {
Jonas Olsson866d6dc2018-05-14 15:30:22214 sb << ", encrypt";
Stefan Holmer1acbd682017-09-01 13:29:28215 }
Jonas Olsson866d6dc2018-05-14 15:30:22216 sb << '}';
217 return sb.str();
Stefan Holmer1acbd682017-09-01 13:29:28218}
219
Markus Handelldfeb0df2020-03-16 21:20:47220bool RtpExtension::IsSupportedForAudio(absl::string_view uri) {
Evan Shrubsole2f5c2662025-05-12 07:43:09221 return uri == RtpExtension::kAudioLevelUri ||
222 uri == RtpExtension::kAbsSendTimeUri ||
223 uri == RtpExtension::kAbsoluteCaptureTimeUri ||
224 uri == RtpExtension::kTransportSequenceNumberUri ||
225 uri == RtpExtension::kTransportSequenceNumberV2Uri ||
226 uri == RtpExtension::kMidUri || uri == RtpExtension::kRidUri ||
227 uri == RtpExtension::kRepairedRidUri;
Stefan Holmer1acbd682017-09-01 13:29:28228}
229
Markus Handelldfeb0df2020-03-16 21:20:47230bool RtpExtension::IsSupportedForVideo(absl::string_view uri) {
Evan Shrubsole2f5c2662025-05-12 07:43:09231 return uri == RtpExtension::kTimestampOffsetUri ||
232 uri == RtpExtension::kAbsSendTimeUri ||
233 uri == RtpExtension::kAbsoluteCaptureTimeUri ||
234 uri == RtpExtension::kVideoRotationUri ||
235 uri == RtpExtension::kTransportSequenceNumberUri ||
236 uri == RtpExtension::kTransportSequenceNumberV2Uri ||
237 uri == RtpExtension::kPlayoutDelayUri ||
238 uri == RtpExtension::kVideoContentTypeUri ||
239 uri == RtpExtension::kVideoTimingUri || uri == RtpExtension::kMidUri ||
240 uri == RtpExtension::kGenericFrameDescriptorUri00 ||
241 uri == RtpExtension::kDependencyDescriptorUri ||
242 uri == RtpExtension::kColorSpaceUri || uri == RtpExtension::kRidUri ||
243 uri == RtpExtension::kRepairedRidUri ||
244 uri == RtpExtension::kVideoLayersAllocationUri ||
245 uri == RtpExtension::kVideoFrameTrackingIdUri ||
246 uri == RtpExtension::kCorruptionDetectionUri;
Stefan Holmer1acbd682017-09-01 13:29:28247}
248
Markus Handelldfeb0df2020-03-16 21:20:47249bool RtpExtension::IsEncryptionSupported(absl::string_view uri) {
Lennart Grahl0d0ed762021-05-17 14:06:37250 return
251#if defined(ENABLE_EXTERNAL_AUTH)
252 // TODO(jbauch): Figure out a way to always allow "kAbsSendTimeUri"
253 // here and filter out later if external auth is really used in
254 // srtpfilter. External auth is used by Chromium and replaces the
255 // extension header value of "kAbsSendTimeUri", so it must not be
256 // encrypted (which can't be done by Chromium).
Harald Alvestrand3d120662025-06-11 07:34:39257 uri != RtpExtension::kAbsSendTimeUri &&
Stefan Holmer1acbd682017-09-01 13:29:28258#endif
Evan Shrubsole2f5c2662025-05-12 07:43:09259 uri != RtpExtension::kEncryptHeaderExtensionsUri;
Lennart Grahl0d0ed762021-05-17 14:06:37260}
261
262// Returns whether a header extension with the given URI exists.
263// Note: This does not differentiate between encrypted and non-encrypted
264// extensions, so use with care!
265static bool HeaderExtensionWithUriExists(
266 const std::vector<RtpExtension>& extensions,
267 absl::string_view uri) {
268 for (const auto& extension : extensions) {
269 if (extension.uri == uri) {
270 return true;
271 }
272 }
273 return false;
274}
275
276const RtpExtension* RtpExtension::FindHeaderExtensionByUri(
277 const std::vector<RtpExtension>& extensions,
278 absl::string_view uri,
279 Filter filter) {
Evan Shrubsole2f5c2662025-05-12 07:43:09280 const RtpExtension* fallback_extension = nullptr;
Lennart Grahl0d0ed762021-05-17 14:06:37281 for (const auto& extension : extensions) {
282 if (extension.uri != uri) {
283 continue;
284 }
285
286 switch (filter) {
287 case kDiscardEncryptedExtension:
288 // We only accept an unencrypted extension.
289 if (!extension.encrypt) {
290 return &extension;
291 }
292 break;
293
294 case kPreferEncryptedExtension:
295 // We prefer an encrypted extension but we can fall back to an
296 // unencrypted extension.
297 if (extension.encrypt) {
298 return &extension;
299 } else {
300 fallback_extension = &extension;
301 }
302 break;
303
304 case kRequireEncryptedExtension:
305 // We only accept an encrypted extension.
306 if (extension.encrypt) {
307 return &extension;
308 }
309 break;
310 }
311 }
312
313 // Returning fallback extension (if any)
314 return fallback_extension;
Lennart Grahla7433032021-04-09 20:05:06315}
316
Lennart Grahl0d0ed762021-05-17 14:06:37317const RtpExtension* RtpExtension::FindHeaderExtensionByUriAndEncryption(
318 const std::vector<RtpExtension>& extensions,
319 absl::string_view uri,
320 bool encrypt) {
Lennart Grahla7433032021-04-09 20:05:06321 for (const auto& extension : extensions) {
Lennart Grahl0d0ed762021-05-17 14:06:37322 if (extension.uri == uri && extension.encrypt == encrypt) {
Stefan Holmer1acbd682017-09-01 13:29:28323 return &extension;
324 }
325 }
326 return nullptr;
327}
328
Lennart Grahl0d0ed762021-05-17 14:06:37329const std::vector<RtpExtension> RtpExtension::DeduplicateHeaderExtensions(
330 const std::vector<RtpExtension>& extensions,
331 Filter filter) {
Stefan Holmer1acbd682017-09-01 13:29:28332 std::vector<RtpExtension> filtered;
Stefan Holmer1acbd682017-09-01 13:29:28333
Lennart Grahl0d0ed762021-05-17 14:06:37334 // If we do not discard encrypted extensions, add them first
335 if (filter != kDiscardEncryptedExtension) {
336 for (const auto& extension : extensions) {
337 if (!extension.encrypt) {
338 continue;
339 }
340 if (!HeaderExtensionWithUriExists(filtered, extension.uri)) {
341 filtered.push_back(extension);
342 }
Stefan Holmer1acbd682017-09-01 13:29:28343 }
344 }
Lennart Grahl0d0ed762021-05-17 14:06:37345
346 // If we do not require encrypted extensions, add missing, non-encrypted
347 // extensions.
348 if (filter != kRequireEncryptedExtension) {
349 for (const auto& extension : extensions) {
350 if (extension.encrypt) {
351 continue;
352 }
353 if (!HeaderExtensionWithUriExists(filtered, extension.uri)) {
354 filtered.push_back(extension);
355 }
356 }
357 }
358
Tomas Gunnarssonc69453d2022-01-06 12:36:04359 // Sort the returned vector to make comparisons of header extensions reliable.
360 // In order of priority, we sort by uri first, then encrypt and id last.
361 std::sort(filtered.begin(), filtered.end(),
362 [](const RtpExtension& a, const RtpExtension& b) {
363 return std::tie(a.uri, a.encrypt, a.id) <
364 std::tie(b.uri, b.encrypt, b.id);
365 });
366
Stefan Holmer1acbd682017-09-01 13:29:28367 return filtered;
368}
Shigemasa Watanabe63c20e92025-10-18 10:18:53369
370bool RtpParameters::IsMixedCodec() const {
371 std::optional<std::optional<RtpCodec>> first_codec;
372 for (const RtpEncodingParameters& encoding : encodings) {
373 if (!encoding.active) {
374 continue;
375 }
376 if (!first_codec) {
377 first_codec = encoding.codec;
378 continue;
379 }
380 if (*first_codec != encoding.codec) {
381 return true;
382 }
383 }
384 return false;
385}
386
Stefan Holmer1acbd682017-09-01 13:29:28387} // namespace webrtc