blob: f989d28f726da2bc2be4d3813be80baa1ffb96a2 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/media_session.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
Elad Alon157540a2019-02-08 23:37:52 +010013#include <algorithm>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve Anton64b626b2019-01-28 17:25:26 -080021#include "absl/algorithm/container.h"
Steve Anton5c72e712018-12-10 14:25:30 -080022#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020023#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020024#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "media/base/media_constants.h"
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +020028#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "p2p/base/p2p_constants.h"
30#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020031#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/rtp_media_utils.h"
33#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/checks.h"
35#include "rtc_base/helpers.h"
36#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020037#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080038#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080041
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080042using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080043using webrtc::RtpTransceiverDirection;
44
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046
Benjamin Wrighta54daf12018-10-11 15:33:17 -070047void GetSupportedSdesCryptoSuiteNames(
48 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
49 const webrtc::CryptoOptions& crypto_options,
50 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070052 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080053 for (const auto crypto : crypto_suites) {
54 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
55 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080056}
Elad Alon157540a2019-02-08 23:37:52 +010057
terelius8c011e52016-04-26 05:28:11 -070058} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60namespace cricket {
61
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062// RTP Profile names
63// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
64// RFC4585
65const char kMediaProtocolAvpf[] = "RTP/AVPF";
66// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000067const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
68
deadbeeff3938292015-07-15 12:20:53 -070069// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
70// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071const char kMediaProtocolSavpf[] = "RTP/SAVPF";
72
deadbeef8b7e9ad2017-05-25 09:38:55 -070073// Note that the below functions support some protocol strings purely for
74// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
75// and Interoperability.
76
77static bool IsDtlsRtp(const std::string& protocol) {
78 // Most-likely values first.
79 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
80 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
81}
82
83static bool IsPlainRtp(const std::string& protocol) {
84 // Most-likely values first.
85 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
86 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
87}
88
Steve Anton1d03a752017-11-27 14:30:09 -080089static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
90 RtpTransceiverDirection offer,
91 RtpTransceiverDirection wants) {
92 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
93 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
94 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
95 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
96 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
97 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070098}
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100static bool IsMediaContentOfType(const ContentInfo* content,
101 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800102 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103 return false;
104 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800105 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106}
107
Yves Gerey665174f2018-06-19 15:03:05 +0200108static bool CreateCryptoParams(int tag,
109 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700110 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700111 int key_len;
112 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200113 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
114 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return false;
116 }
jbauchcb560652016-08-04 05:20:32 -0700117
118 int master_key_len = key_len + salt_len;
119 std::string master_key;
120 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
121 return false;
122 }
123
kwiberg352444f2016-11-28 15:58:53 -0800124 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700125 std::string key = rtc::Base64::Encode(master_key);
126
Steve Anton3a66edf2018-09-10 12:57:37 -0700127 crypto_out->tag = tag;
128 crypto_out->cipher_suite = cipher;
129 crypto_out->key_params = kInline;
130 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 return true;
132}
133
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700135 CryptoParamsVec* cryptos_out) {
136 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Steve Anton3a66edf2018-09-10 12:57:37 -0700138 cryptos_out->resize(size + 1);
139 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140}
141
142void AddMediaCryptos(const CryptoParamsVec& cryptos,
143 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700144 for (const CryptoParams& crypto : cryptos) {
145 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 }
147}
148
149bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
150 MediaContentDescription* media) {
151 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700152 for (const std::string& crypto_suite : crypto_suites) {
153 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 return false;
155 }
156 }
157 AddMediaCryptos(cryptos, media);
158 return true;
159}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
zhihuang1c378ed2017-08-17 14:10:50 -0700161const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800162 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700163 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800165 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
168bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
169 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700170 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800171 auto it = absl::c_find_if(
172 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700173 if (it == cryptos.end()) {
174 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700176 *crypto_out = *it;
177 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178}
179
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700180// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
181// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700182void GetSupportedAudioSdesCryptoSuites(
183 const webrtc::CryptoOptions& crypto_options,
184 std::vector<int>* crypto_suites) {
185 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
188 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700189 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700190 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
191 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800192 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193}
194
deadbeef7914b8c2017-04-21 03:23:33 -0700195void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700196 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800197 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700198 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
199 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200}
201
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700202void GetSupportedVideoSdesCryptoSuites(
203 const webrtc::CryptoOptions& crypto_options,
204 std::vector<int>* crypto_suites) {
205 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700206 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
207 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
208 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800209 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
deadbeef7914b8c2017-04-21 03:23:33 -0700212void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700213 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800214 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700215 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedDataSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
227}
228
229void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700231 std::vector<std::string>* crypto_suite_names) {
232 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800234}
235
jbauchcb560652016-08-04 05:20:32 -0700236// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700237// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
238// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700239// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240static bool SelectCrypto(const MediaContentDescription* offer,
241 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700242 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700243 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
245 const CryptoParamsVec& cryptos = offer->cryptos();
246
Steve Anton3a66edf2018-09-10 12:57:37 -0700247 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700248 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700249 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
250 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
251 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700252 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700253 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 }
255 }
256 return false;
257}
258
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800260static StreamParamsVec GetCurrentStreamParams(
261 const std::vector<const ContentInfo*>& active_local_contents) {
262 StreamParamsVec stream_params;
263 for (const ContentInfo* content : active_local_contents) {
264 for (const StreamParams& params : content->media_description()->streams()) {
265 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 }
267 }
Steve Anton5c72e712018-12-10 14:25:30 -0800268 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269}
270
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000271// Filters the data codecs for the data channel type.
272void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
273 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700274 const char* codec_name =
275 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700276 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
277 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200278 return absl::EqualsIgnoreCase(codec.name,
279 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700280 }),
281 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000282}
283
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284template <typename IdStruct>
285class UsedIds {
286 public:
287 UsedIds(int min_allowed_id, int max_allowed_id)
288 : min_allowed_id_(min_allowed_id),
289 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200290 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291
292 // Loops through all Id in |ids| and changes its id if it is
293 // already in use by another IdStruct. Call this methods with all Id
294 // in a session description to make sure no duplicate ids exists.
295 // Note that typename Id must be a type of IdStruct.
296 template <typename Id>
297 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700298 for (const Id& id : *ids) {
299 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 }
301 }
302
303 // Finds and sets an unused id if the |idstruct| id is already in use.
304 void FindAndSetIdUsed(IdStruct* idstruct) {
305 const int original_id = idstruct->id;
306 int new_id = idstruct->id;
307
308 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
309 // If the original id is not in range - this is an id that can't be
310 // dynamically changed.
311 return;
312 }
313
314 if (IsIdUsed(original_id)) {
315 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100316 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
317 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318 idstruct->id = new_id;
319 }
320 SetIdUsed(new_id);
321 }
322
323 private:
324 // Returns the first unused id in reverse order.
325 // This hopefully reduce the risk of more collisions. We want to change the
326 // default ids as little as possible.
327 int FindUnusedId() {
328 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
329 --next_id_;
330 }
nisseede5da42017-01-12 05:15:36 -0800331 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 return next_id_;
333 }
334
Yves Gerey665174f2018-06-19 15:03:05 +0200335 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336
Yves Gerey665174f2018-06-19 15:03:05 +0200337 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338
339 const int min_allowed_id_;
340 const int max_allowed_id_;
341 int next_id_;
342 std::set<int> id_set_;
343};
344
345// Helper class used for finding duplicate RTP payload types among audio, video
346// and data codecs. When bundle is used the payload types may not collide.
347class UsedPayloadTypes : public UsedIds<Codec> {
348 public:
349 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200350 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351
352 private:
353 static const int kDynamicPayloadTypeMin = 96;
354 static const int kDynamicPayloadTypeMax = 127;
355};
356
357// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200358// audio and video extensions. Only applies to one-byte header extensions at the
359// moment. ids > 14 will always be reported as available.
360// TODO(kron): This class needs to be refactored when we start to send two-byte
361// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700362class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363 public:
364 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200365 : UsedIds<webrtc::RtpExtension>(
366 webrtc::RtpExtension::kMinId,
367 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
369 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370};
371
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
373 const SenderOptions& sender,
374 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800375 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800376 bool include_flexfec_stream,
377 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800378 StreamParams result;
379 result.id = sender.track_id;
380
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800381 // TODO(brandtr): Update when we support multistream protection.
382 if (include_flexfec_stream && sender.num_sim_layers > 1) {
383 include_flexfec_stream = false;
384 RTC_LOG(LS_WARNING)
385 << "Our FlexFEC implementation only supports protecting "
386 "a single media streams. This session has multiple "
387 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800388 }
389
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800390 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
391 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800392
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800393 result.cname = rtcp_cname;
394 result.set_stream_ids(sender.stream_ids);
395
396 return result;
397}
398
399static bool ValidateSimulcastLayers(
400 const std::vector<RidDescription>& rids,
401 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800402 return absl::c_all_of(
403 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
404 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
405 return rid.rid == layer.rid;
406 });
407 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800408}
409
410static StreamParams CreateStreamParamsForNewSenderWithRids(
411 const SenderOptions& sender,
412 const std::string& rtcp_cname) {
413 RTC_DCHECK(!sender.rids.empty());
414 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
415 << "RIDs are the compliant way to indicate simulcast.";
416 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
417 StreamParams result;
418 result.id = sender.track_id;
419 result.cname = rtcp_cname;
420 result.set_stream_ids(sender.stream_ids);
421
422 // More than one rid should be signaled.
423 if (sender.rids.size() > 1) {
424 result.set_rids(sender.rids);
425 }
426
427 return result;
428}
429
430// Adds SimulcastDescription if indicated by the media description options.
431// MediaContentDescription should already be set up with the send rids.
432static void AddSimulcastToMediaDescription(
433 const MediaDescriptionOptions& media_description_options,
434 MediaContentDescription* description) {
435 RTC_DCHECK(description);
436
437 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800438 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
439 return !params.has_rids();
440 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800441 return;
442 }
443
444 RTC_DCHECK_EQ(1, description->streams().size())
445 << "RIDs are only supported in Unified Plan semantics.";
446 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
447 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
448 description->type() == MediaType::MEDIA_TYPE_VIDEO);
449
450 // One RID or less indicates that simulcast is not needed.
451 if (description->streams()[0].rids().size() <= 1) {
452 return;
453 }
454
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800455 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800456 SimulcastDescription simulcast;
457 simulcast.send_layers() =
458 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800459 description->set_simulcast_description(simulcast);
460}
461
zhihuang1c378ed2017-08-17 14:10:50 -0700462// Adds a StreamParams for each SenderOptions in |sender_options| to
463// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464// |current_params| - All currently known StreamParams of any media type.
465template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700466static bool AddStreamParams(
467 const std::vector<SenderOptions>& sender_options,
468 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800469 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700470 StreamParamsVec* current_streams,
471 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700472 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200473 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700474 return true;
475 }
476
Noah Richards2e7a0982015-05-18 14:02:54 -0700477 const bool include_rtx_streams =
478 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479
brandtr03d5fb12016-11-22 03:37:59 -0800480 const bool include_flexfec_stream =
481 ContainsFlexfecCodec(content_description->codecs());
482
zhihuang1c378ed2017-08-17 14:10:50 -0700483 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 // groupid is empty for StreamParams generated using
485 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700486 StreamParams* param =
487 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000488 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700489 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800490 StreamParams stream_param =
491 sender.rids.empty()
492 ?
493 // Signal SSRCs and legacy simulcast (if requested).
494 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800495 sender, rtcp_cname, include_rtx_streams,
496 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800497 :
498 // Signal RIDs and spec-compliant simulcast (if requested).
499 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
500
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 content_description->AddStream(stream_param);
502
503 // Store the new StreamParams in current_streams.
504 // This is necessary so that we can use the CNAME for other media types.
505 current_streams->push_back(stream_param);
506 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700507 // Use existing generated SSRCs/groups, but update the sync_label if
508 // necessary. This may be needed if a MediaStreamTrack was moved from one
509 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800510 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000511 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 }
513 }
514 return true;
515}
516
517// Updates the transport infos of the |sdesc| according to the given
518// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800519// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
520// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
522 SessionDescription* sdesc) {
523 // The bundle should not be empty.
524 if (!sdesc || !bundle_group.FirstContentName()) {
525 return false;
526 }
527
528 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700529 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 const TransportInfo* selected_transport_info =
531 sdesc->GetTransportInfoByName(selected_content_name);
532 if (!selected_transport_info) {
533 return false;
534 }
535
536 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700537 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700539 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800541 ConnectionRole selected_connection_role =
542 selected_transport_info->description.connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700543 const absl::optional<OpaqueTransportParameters>& selected_opaque_parameters =
544 selected_transport_info->description.opaque_parameters;
Steve Anton3a66edf2018-09-10 12:57:37 -0700545 for (TransportInfo& transport_info : sdesc->transport_infos()) {
546 if (bundle_group.HasContentName(transport_info.content_name) &&
547 transport_info.content_name != selected_content_name) {
548 transport_info.description.ice_ufrag = selected_ufrag;
549 transport_info.description.ice_pwd = selected_pwd;
550 transport_info.description.connection_role = selected_connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700551 transport_info.description.opaque_parameters = selected_opaque_parameters;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 }
553 }
554 return true;
555}
556
557// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
558// sets it to |cryptos|.
559static bool GetCryptosByName(const SessionDescription* sdesc,
560 const std::string& content_name,
561 CryptoParamsVec* cryptos) {
562 if (!sdesc || !cryptos) {
563 return false;
564 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800566 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 return false;
568 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800569 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 return true;
571}
572
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
574// which are not available in |filter|.
575static void PruneCryptos(const CryptoParamsVec& filter,
576 CryptoParamsVec* target_cryptos) {
577 if (!target_cryptos) {
578 return;
579 }
tzik21995802018-04-26 17:38:28 +0900580
581 target_cryptos->erase(
582 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
583 // Returns true if the |crypto|'s cipher_suite is not
584 // found in |filter|.
585 [&filter](const CryptoParams& crypto) {
586 for (const CryptoParams& entry : filter) {
587 if (entry.cipher_suite == crypto.cipher_suite)
588 return false;
589 }
590 return true;
591 }),
592 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593}
594
595static bool IsRtpContent(SessionDescription* sdesc,
596 const std::string& content_name) {
597 bool is_rtp = false;
598 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800599 if (content && content->media_description()) {
600 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 }
602 return is_rtp;
603}
604
605// Updates the crypto parameters of the |sdesc| according to the given
606// |bundle_group|. The crypto parameters of all the contents within the
607// |bundle_group| should be updated to use the common subset of the
608// available cryptos.
609static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
610 SessionDescription* sdesc) {
611 // The bundle should not be empty.
612 if (!sdesc || !bundle_group.FirstContentName()) {
613 return false;
614 }
615
wu@webrtc.org78187522013-10-07 23:32:02 +0000616 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 // Get the common cryptos.
618 const ContentNames& content_names = bundle_group.content_names();
619 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700620 bool first = true;
621 for (const std::string& content_name : content_names) {
622 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 continue;
624 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000625 // The common cryptos are needed if any of the content does not have DTLS
626 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700627 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000628 common_cryptos_needed = true;
629 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700630 if (first) {
631 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700633 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 return false;
635 }
636 if (common_cryptos.empty()) {
637 // If there's no crypto params, we should just return.
638 return true;
639 }
640 } else {
641 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700642 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 return false;
644 }
645 PruneCryptos(cryptos, &common_cryptos);
646 }
647 }
648
wu@webrtc.org78187522013-10-07 23:32:02 +0000649 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 return false;
651 }
652
653 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700654 for (const std::string& content_name : content_names) {
655 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 continue;
657 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700658 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800660 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 if (!media_desc) {
662 return false;
663 }
664 media_desc->set_cryptos(common_cryptos);
665 }
666 }
667 return true;
668}
669
Steve Anton5c72e712018-12-10 14:25:30 -0800670static std::vector<const ContentInfo*> GetActiveContents(
671 const SessionDescription& description,
672 const MediaSessionOptions& session_options) {
673 std::vector<const ContentInfo*> active_contents;
674 for (size_t i = 0; i < description.contents().size(); ++i) {
675 RTC_DCHECK_LT(i, session_options.media_description_options.size());
676 const ContentInfo& content = description.contents()[i];
677 const MediaDescriptionOptions& media_options =
678 session_options.media_description_options[i];
679 if (!content.rejected && !media_options.stopped &&
680 content.name == media_options.mid) {
681 active_contents.push_back(&content);
682 }
683 }
684 return active_contents;
685}
686
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687template <class C>
688static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800689 for (const auto& codec : codecs) {
690 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 return true;
692 }
693 }
694 return false;
695}
696
697template <class C>
698static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200699 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700}
701
brandtr03d5fb12016-11-22 03:37:59 -0800702template <class C>
703static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
704 for (const auto& codec : codecs) {
705 if (IsFlexfecCodec(codec)) {
706 return true;
707 }
708 }
709 return false;
710}
711
712template <class C>
713static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200714 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800715}
716
zhihuang1c378ed2017-08-17 14:10:50 -0700717// Create a media content to be offered for the given |sender_options|,
718// according to the given options.rtcp_mux, session_options.is_muc, codecs,
719// secure_transport, crypto, and current_streams. If we don't currently have
720// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
721// created (according to crypto_suites). The created content is added to the
722// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200723static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800724 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700725 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000726 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 const CryptoParamsVec* current_cryptos,
728 const std::vector<std::string>& crypto_suites,
729 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800730 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200732 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700733 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700734 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
735 offer->set_rtcp_reduced_size(true);
736 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 offer->set_rtp_header_extensions(rtp_extensions);
738
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800739 AddSimulcastToMediaDescription(media_description_options, offer);
740
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 if (secure_policy != SEC_DISABLED) {
742 if (current_cryptos) {
743 AddMediaCryptos(*current_cryptos, offer);
744 }
745 if (offer->cryptos().empty()) {
746 if (!CreateMediaCryptos(crypto_suites, offer)) {
747 return false;
748 }
749 }
750 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751
deadbeef7af91dd2016-12-13 11:29:11 -0800752 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 return false;
754 }
755 return true;
756}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200757template <class C>
758static bool CreateMediaContentOffer(
759 const MediaDescriptionOptions& media_description_options,
760 const MediaSessionOptions& session_options,
761 const std::vector<C>& codecs,
762 const SecurePolicy& secure_policy,
763 const CryptoParamsVec* current_cryptos,
764 const std::vector<std::string>& crypto_suites,
765 const RtpHeaderExtensions& rtp_extensions,
766 UniqueRandomIdGenerator* ssrc_generator,
767 StreamParamsVec* current_streams,
768 MediaContentDescriptionImpl<C>* offer) {
769 offer->AddCodecs(codecs);
770 if (!AddStreamParams(media_description_options.sender_options,
771 session_options.rtcp_cname, ssrc_generator,
772 current_streams, offer)) {
773 return false;
774 }
775
776 return CreateContentOffer(media_description_options, session_options,
777 secure_policy, current_cryptos, crypto_suites,
778 rtp_extensions, ssrc_generator, current_streams,
779 offer);
780}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781
782template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000783static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800784 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000785 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800786 const int codec2_id) {
787 const C* codec1 = FindCodecById(codecs1, codec1_id);
788 const C* codec2 = FindCodecById(codecs2, codec2_id);
789 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000790}
791
792template <class C>
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200793static void NegotiatePacketization(const C& local_codec,
794 const C& remote_codec,
795 C* negotiated_codec) {}
796
797template <>
798void NegotiatePacketization(const VideoCodec& local_codec,
799 const VideoCodec& remote_codec,
800 VideoCodec* negotiated_codec) {
801 negotiated_codec->packetization =
802 VideoCodec::IntersectPacketization(local_codec, remote_codec);
803}
804
805template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806static void NegotiateCodecs(const std::vector<C>& local_codecs,
807 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200808 std::vector<C>* negotiated_codecs,
809 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800810 for (const C& ours : local_codecs) {
811 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700812 // Note that we intentionally only find one matching codec for each of our
813 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800814 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
815 C negotiated = ours;
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200816 NegotiatePacketization(ours, theirs, &negotiated);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800817 negotiated.IntersectFeedbackParams(theirs);
818 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800819 const auto apt_it =
820 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800821 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800822 RTC_DCHECK(apt_it != theirs.params.end());
823 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824 }
Niels Möller039743e2018-10-23 10:07:25 +0200825 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800826 webrtc::H264::GenerateProfileLevelIdForAnswer(
827 ours.params, theirs.params, &negotiated.params);
828 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800829 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700830 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800831 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 }
833 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200834 if (keep_offer_order) {
835 // RFC3264: Although the answerer MAY list the formats in their desired
836 // order of preference, it is RECOMMENDED that unless there is a
837 // specific reason, the answerer list formats in the same relative order
838 // they were present in the offer.
839 // This can be skipped when the transceiver has any codec preferences.
840 std::unordered_map<int, int> payload_type_preferences;
841 int preference = static_cast<int>(offered_codecs.size() + 1);
842 for (const C& codec : offered_codecs) {
843 payload_type_preferences[codec.id] = preference--;
844 }
845 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
846 const C& b) {
847 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
848 });
deadbeef67cf2c12016-04-13 10:07:16 -0700849 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850}
851
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852// Finds a codec in |codecs2| that matches |codec_to_match|, which is
853// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
854// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800856static bool FindMatchingCodec(const std::vector<C>& codecs1,
857 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858 const C& codec_to_match,
859 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700860 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
861 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800862 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
863 return &codec == &codec_to_match;
864 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800865 for (const C& potential_match : codecs2) {
866 if (potential_match.Matches(codec_to_match)) {
867 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800868 int apt_value_1 = 0;
869 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800870 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
871 &apt_value_1) ||
872 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
873 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100874 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800875 continue;
876 }
877 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
878 apt_value_2)) {
879 continue;
880 }
881 }
882 if (found_codec) {
883 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884 }
885 return true;
886 }
887 }
888 return false;
889}
890
zhihuang1c378ed2017-08-17 14:10:50 -0700891// Find the codec in |codec_list| that |rtx_codec| is associated with.
892template <class C>
893static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
894 const C& rtx_codec) {
895 std::string associated_pt_str;
896 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
897 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100898 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
899 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700900 return nullptr;
901 }
902
903 int associated_pt;
904 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100905 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
906 << " of RTX codec " << rtx_codec.name
907 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700908 return nullptr;
909 }
910
911 // Find the associated reference codec for the reference RTX codec.
912 const C* associated_codec = FindCodecById(codec_list, associated_pt);
913 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100914 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
915 << associated_pt << " for RTX codec " << rtx_codec.name
916 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700917 }
918 return associated_codec;
919}
920
921// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000922// already exist in |offered_codecs| and ensure the payload types don't
923// collide.
924template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700925static void MergeCodecs(const std::vector<C>& reference_codecs,
926 std::vector<C>* offered_codecs,
927 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000928 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800929 for (const C& reference_codec : reference_codecs) {
930 if (!IsRtxCodec(reference_codec) &&
931 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
932 reference_codec, nullptr)) {
933 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 used_pltypes->FindAndSetIdUsed(&codec);
935 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000936 }
937 }
938
939 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800940 for (const C& reference_codec : reference_codecs) {
941 if (IsRtxCodec(reference_codec) &&
942 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
943 reference_codec, nullptr)) {
944 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700945 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700946 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700947 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700948 continue;
949 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800950 // Find a codec in the offered list that matches the reference codec.
951 // Its payload type may be different than the reference codec.
952 C matching_codec;
953 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800954 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100955 RTC_LOG(LS_WARNING)
956 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800957 continue;
958 }
959
960 rtx_codec.params[kCodecParamAssociatedPayloadType] =
961 rtc::ToString(matching_codec.id);
962 used_pltypes->FindAndSetIdUsed(&rtx_codec);
963 offered_codecs->push_back(rtx_codec);
964 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 }
966}
967
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200968template <typename Codecs>
969static Codecs MatchCodecPreference(
970 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
971 const Codecs& codecs) {
972 Codecs filtered_codecs;
973 std::set<std::string> kept_codecs_ids;
974 bool want_rtx = false;
975
976 for (const auto& codec_preference : codec_preferences) {
977 auto found_codec = absl::c_find_if(
978 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
979 webrtc::RtpCodecParameters codec_parameters =
980 codec.ToCodecParameters();
981 return codec_parameters.name == codec_preference.name &&
982 codec_parameters.kind == codec_preference.kind &&
983 codec_parameters.num_channels ==
984 codec_preference.num_channels &&
985 codec_parameters.clock_rate == codec_preference.clock_rate &&
986 codec_parameters.parameters == codec_preference.parameters;
987 });
988
989 if (found_codec != codecs.end()) {
990 filtered_codecs.push_back(*found_codec);
991 kept_codecs_ids.insert(std::to_string(found_codec->id));
992 } else if (IsRtxCodec(codec_preference)) {
993 want_rtx = true;
994 }
995 }
996
997 if (want_rtx) {
998 for (const auto& codec : codecs) {
999 if (IsRtxCodec(codec)) {
1000 const auto apt =
1001 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
1002 if (apt != codec.params.end() &&
1003 kept_codecs_ids.count(apt->second) > 0) {
1004 filtered_codecs.push_back(codec);
1005 }
1006 }
1007 }
1008 }
1009
1010 return filtered_codecs;
1011}
1012
zhihuang1c378ed2017-08-17 14:10:50 -07001013static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
1014 const webrtc::RtpExtension& ext_to_match,
1015 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -08001016 auto it = absl::c_find_if(
1017 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
1018 // We assume that all URIs are given in a canonical
1019 // format.
1020 return extension.uri == ext_to_match.uri &&
1021 extension.encrypt == ext_to_match.encrypt;
1022 });
Steve Anton3a66edf2018-09-10 12:57:37 -07001023 if (it == extensions.end()) {
1024 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001025 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001026 if (found_extension) {
1027 *found_extension = *it;
1028 }
1029 return true;
zhihuang1c378ed2017-08-17 14:10:50 -07001030}
1031
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -07001033 const webrtc::RtpExtension& ext_to_match,
1034 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -07001035 // We assume that all URIs are given in a canonical format.
1036 const webrtc::RtpExtension* found =
1037 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
1038 ext_to_match.uri);
1039 if (!found) {
1040 return false;
1041 }
1042 if (found_extension) {
1043 *found_extension = *found;
1044 }
1045 return true;
1046}
1047
1048static bool FindByUriWithEncryptionPreference(
1049 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001050 const webrtc::RtpExtension& ext_to_match,
1051 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001052 webrtc::RtpExtension* found_extension) {
1053 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001054 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001056 if (extension.uri == ext_to_match.uri) {
1057 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001058 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001059 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001060 }
1061 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001063 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 }
1065 }
jbauch5869f502017-06-29 12:31:36 -07001066 if (unencrypted_extension) {
1067 if (found_extension) {
1068 *found_extension = *unencrypted_extension;
1069 }
1070 return true;
1071 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 return false;
1073}
1074
zhihuang1c378ed2017-08-17 14:10:50 -07001075// Adds all extensions from |reference_extensions| to |offered_extensions| that
1076// don't already exist in |offered_extensions| and ensure the IDs don't
1077// collide. If an extension is added, it's also added to |regular_extensions| or
1078// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1079// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1080// |offered_extensions| is for either audio or video while |regular_extensions|
1081// and |encrypted_extensions| are used for both audio and video. There could be
1082// overlap between audio extensions and video extensions.
1083static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1084 RtpHeaderExtensions* offered_extensions,
1085 RtpHeaderExtensions* regular_extensions,
1086 RtpHeaderExtensions* encrypted_extensions,
1087 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001088 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001089 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1090 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001091 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001092 if (reference_extension.encrypt) {
1093 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1094 &existing)) {
1095 offered_extensions->push_back(existing);
1096 } else {
1097 used_ids->FindAndSetIdUsed(&reference_extension);
1098 encrypted_extensions->push_back(reference_extension);
1099 offered_extensions->push_back(reference_extension);
1100 }
olka3c747662017-08-17 06:50:32 -07001101 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001102 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1103 &existing)) {
1104 offered_extensions->push_back(existing);
1105 } else {
1106 used_ids->FindAndSetIdUsed(&reference_extension);
1107 regular_extensions->push_back(reference_extension);
1108 offered_extensions->push_back(reference_extension);
1109 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001110 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 }
1112 }
1113}
1114
jbauch5869f502017-06-29 12:31:36 -07001115static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1116 RtpHeaderExtensions* all_extensions,
1117 UsedRtpHeaderExtensionIds* used_ids) {
1118 RtpHeaderExtensions encrypted_extensions;
1119 for (const webrtc::RtpExtension& extension : *extensions) {
1120 webrtc::RtpExtension existing;
1121 // Don't add encrypted extensions again that were already included in a
1122 // previous offer or regular extensions that are also included as encrypted
1123 // extensions.
1124 if (extension.encrypt ||
1125 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1126 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001127 &existing) &&
1128 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001129 continue;
1130 }
1131
1132 if (FindByUri(*all_extensions, extension, &existing)) {
1133 encrypted_extensions.push_back(existing);
1134 } else {
1135 webrtc::RtpExtension encrypted(extension);
1136 encrypted.encrypt = true;
1137 used_ids->FindAndSetIdUsed(&encrypted);
1138 all_extensions->push_back(encrypted);
1139 encrypted_extensions.push_back(encrypted);
1140 }
1141 }
1142 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001143 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001144}
1145
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001146static void NegotiateRtpHeaderExtensions(
1147 const RtpHeaderExtensions& local_extensions,
1148 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001149 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001150 RtpHeaderExtensions* negotiated_extensions) {
1151 // TransportSequenceNumberV2 is not offered by default. The special logic for
1152 // the TransportSequenceNumber extensions works as follows:
1153 // Offer Answer
1154 // V1 V1 if in local_extensions.
1155 // V1 and V2 V2 regardless of local_extensions.
1156 // V2 V2 regardless of local_extensions.
1157 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1158 webrtc::RtpExtension::FindHeaderExtensionByUri(
1159 offered_extensions,
1160 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1161
Steve Anton3a66edf2018-09-10 12:57:37 -07001162 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001163 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001164 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001165 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001166 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001167 if (transport_sequence_number_v2_offer &&
1168 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1169 // Don't respond to
1170 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1171 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001172 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001173 continue;
1174 } else {
1175 // We respond with their RTP header extension id.
1176 negotiated_extensions->push_back(theirs);
1177 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 }
1179 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001180
1181 if (transport_sequence_number_v2_offer) {
1182 // Respond that we support kTransportSequenceNumberV2Uri.
1183 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1184 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185}
1186
1187static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001188 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1189 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001190 return absl::EqualsIgnoreCase(
1191 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001192 }),
1193 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194}
1195
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001196template <class C>
1197static bool SetCodecsInAnswer(
1198 const MediaContentDescriptionImpl<C>* offer,
1199 const std::vector<C>& local_codecs,
1200 const MediaDescriptionOptions& media_description_options,
1201 const MediaSessionOptions& session_options,
1202 UniqueRandomIdGenerator* ssrc_generator,
1203 StreamParamsVec* current_streams,
1204 MediaContentDescriptionImpl<C>* answer) {
1205 std::vector<C> negotiated_codecs;
1206 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1207 media_description_options.codec_preferences.empty());
1208 answer->AddCodecs(negotiated_codecs);
1209 answer->set_protocol(offer->protocol());
1210 if (!AddStreamParams(media_description_options.sender_options,
1211 session_options.rtcp_cname, ssrc_generator,
1212 current_streams, answer)) {
1213 return false; // Something went seriously wrong.
1214 }
1215 return true;
1216}
1217
zhihuang1c378ed2017-08-17 14:10:50 -07001218// Create a media content to be answered for the given |sender_options|
1219// according to the given session_options.rtcp_mux, session_options.streams,
1220// codecs, crypto, and current_streams. If we don't currently have crypto (in
1221// current_cryptos) and it is enabled (in secure_policy), crypto is created
1222// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1223// negotiated with the offer. If the negotiation fails, this method returns
1224// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001226 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001227 const MediaDescriptionOptions& media_description_options,
1228 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001229 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230 const CryptoParamsVec* current_cryptos,
1231 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001232 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001233 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001236 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001237 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001239 NegotiateRtpHeaderExtensions(
1240 local_rtp_extenstions, offer->rtp_header_extensions(),
1241 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1243
zhihuang1c378ed2017-08-17 14:10:50 -07001244 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001245 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1246 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1247 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248
1249 if (sdes_policy != SEC_DISABLED) {
1250 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001251 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1252 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 if (current_cryptos) {
1254 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1255 }
1256 answer->AddCrypto(crypto);
1257 }
1258 }
1259
deadbeef7af91dd2016-12-13 11:29:11 -08001260 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 return false;
1262 }
1263
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001264 AddSimulcastToMediaDescription(media_description_options, answer);
1265
Steve Anton4e70a722017-11-28 14:57:10 -08001266 answer->set_direction(NegotiateRtpTransceiverDirection(
1267 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 return true;
1269}
1270
1271static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001272 const std::string& protocol,
1273 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001274 // Since not all applications serialize and deserialize the media protocol,
1275 // we will have to accept |protocol| to be empty.
1276 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 return true;
1278 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001279
zhihuangcf5b37c2016-05-05 11:44:35 -07001280 if (type == MEDIA_TYPE_DATA) {
1281 // Check for SCTP, but also for RTP for RTP-based data channels.
1282 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1283 if (secure_transport) {
1284 // Most likely scenarios first.
1285 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1286 IsPlainRtp(protocol);
1287 } else {
1288 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1289 }
1290 }
1291
1292 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1293 // JSEP specifies.
1294 if (secure_transport) {
1295 // Most likely scenarios first.
1296 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1297 } else {
1298 return IsPlainRtp(protocol);
1299 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300}
1301
1302static void SetMediaProtocol(bool secure_transport,
1303 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001304 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001306 else if (secure_transport)
1307 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 else
1309 desc->set_protocol(kMediaProtocolAvpf);
1310}
1311
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001312// Gets the TransportInfo of the given |content_name| from the
1313// |current_description|. If doesn't exist, returns a new one.
1314static const TransportDescription* GetTransportDescription(
1315 const std::string& content_name,
1316 const SessionDescription* current_description) {
1317 const TransportDescription* desc = NULL;
1318 if (current_description) {
1319 const TransportInfo* info =
1320 current_description->GetTransportInfoByName(content_name);
1321 if (info) {
1322 desc = &info->description;
1323 }
1324 }
1325 return desc;
1326}
1327
1328// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001329static bool IsDtlsActive(const ContentInfo* content,
1330 const SessionDescription* current_description) {
1331 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001332 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001333 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001334
zhihuang1c378ed2017-08-17 14:10:50 -07001335 size_t msection_index = content - &current_description->contents()[0];
1336
1337 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001338 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001339 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001340
zhihuang1c378ed2017-08-17 14:10:50 -07001341 return current_description->transport_infos()[msection_index]
1342 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001343}
1344
Steve Anton8ffb9c32017-08-31 15:45:38 -07001345void MediaDescriptionOptions::AddAudioSender(
1346 const std::string& track_id,
1347 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001348 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001349 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001350}
1351
Steve Anton8ffb9c32017-08-31 15:45:38 -07001352void MediaDescriptionOptions::AddVideoSender(
1353 const std::string& track_id,
1354 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001355 const std::vector<RidDescription>& rids,
1356 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001357 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001358 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001359 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1360 << "RIDs are the compliant way to indicate simulcast.";
1361 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1362 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1363 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001364}
1365
zhihuang1c378ed2017-08-17 14:10:50 -07001366void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1367 const std::string& stream_id) {
1368 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001369 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1370 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001371 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001372}
1373
Steve Anton8ffb9c32017-08-31 15:45:38 -07001374void MediaDescriptionOptions::AddSenderInternal(
1375 const std::string& track_id,
1376 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001377 const std::vector<RidDescription>& rids,
1378 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001379 int num_sim_layers) {
1380 // TODO(steveanton): Support any number of stream ids.
1381 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001382 SenderOptions options;
1383 options.track_id = track_id;
1384 options.stream_ids = stream_ids;
1385 options.simulcast_layers = simulcast_layers;
1386 options.rids = rids;
1387 options.num_sim_layers = num_sim_layers;
1388 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001389}
1390
zhihuang1c378ed2017-08-17 14:10:50 -07001391bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001392 return absl::c_any_of(
1393 media_description_options,
1394 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001395}
1396
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001398 const TransportDescriptionFactory* transport_desc_factory,
1399 rtc::UniqueRandomIdGenerator* ssrc_generator)
1400 : ssrc_generator_(ssrc_generator),
1401 transport_desc_factory_(transport_desc_factory) {
1402 RTC_DCHECK(ssrc_generator_);
1403}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001404
1405MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1406 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001407 const TransportDescriptionFactory* transport_desc_factory,
1408 rtc::UniqueRandomIdGenerator* ssrc_generator)
1409 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001410 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1411 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001412 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001413 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001415 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001416 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001417}
1418
ossudedfd282016-06-14 07:12:39 -07001419const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1420 const {
ossu075af922016-06-14 03:29:38 -07001421 return audio_sendrecv_codecs_;
1422}
1423
1424const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1425 return audio_send_codecs_;
1426}
1427
1428const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1429 return audio_recv_codecs_;
1430}
1431
1432void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001433 const AudioCodecs& send_codecs,
1434 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001435 audio_send_codecs_ = send_codecs;
1436 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001437 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438}
1439
Amit Hilbuch77938e62018-12-21 09:23:38 -08001440static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1441 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001442
1443 rtc::UniqueNumberGenerator<int> unique_id_generator;
1444 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1445 for (const webrtc::RtpExtension& extension : *extensions) {
1446 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1447 RTC_DCHECK(collision_free);
1448 }
1449
Amit Hilbuch77938e62018-12-21 09:23:38 -08001450 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001451 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1452 unique_id_generator()));
1453 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1454 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001455 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001456 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001457}
1458
1459RtpHeaderExtensions
1460MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1461 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1462 if (is_unified_plan_) {
1463 AddUnifiedPlanExtensions(&extensions);
1464 }
1465
1466 return extensions;
1467}
1468
1469RtpHeaderExtensions
1470MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1471 RtpHeaderExtensions extensions = video_rtp_extensions_;
1472 if (is_unified_plan_) {
1473 AddUnifiedPlanExtensions(&extensions);
1474 }
1475
1476 return extensions;
1477}
1478
Steve Anton6fe1fba2018-12-11 10:15:23 -08001479std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001480 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001482 // Must have options for each existing section.
1483 if (current_description) {
1484 RTC_DCHECK_LE(current_description->contents().size(),
1485 session_options.media_description_options.size());
1486 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001487
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001488 IceCredentialsIterator ice_credentials(
1489 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001490
1491 std::vector<const ContentInfo*> current_active_contents;
1492 if (current_description) {
1493 current_active_contents =
1494 GetActiveContents(*current_description, session_options);
1495 }
1496
1497 StreamParamsVec current_streams =
1498 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499
zhihuang1c378ed2017-08-17 14:10:50 -07001500 AudioCodecs offer_audio_codecs;
1501 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001502 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001503 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001504 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001505
zhihuang1c378ed2017-08-17 14:10:50 -07001506 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001508 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001509 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001510 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001511 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512
1513 RtpHeaderExtensions audio_rtp_extensions;
1514 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001515 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1516 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001517
Steve Anton5c72e712018-12-10 14:25:30 -08001518 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001519
zhihuang1c378ed2017-08-17 14:10:50 -07001520 // Iterate through the media description options, matching with existing media
1521 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001522 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001523 for (const MediaDescriptionOptions& media_description_options :
1524 session_options.media_description_options) {
1525 const ContentInfo* current_content = nullptr;
1526 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001527 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001528 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001529 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001530 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001531 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001532 media_description_options.type));
1533 }
1534 switch (media_description_options.type) {
1535 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001536 if (!AddAudioContentForOffer(
1537 media_description_options, session_options, current_content,
1538 current_description, audio_rtp_extensions, offer_audio_codecs,
1539 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001540 return nullptr;
1541 }
1542 break;
1543 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001544 if (!AddVideoContentForOffer(
1545 media_description_options, session_options, current_content,
1546 current_description, video_rtp_extensions, offer_video_codecs,
1547 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001548 return nullptr;
1549 }
1550 break;
1551 case MEDIA_TYPE_DATA:
1552 if (!AddDataContentForOffer(media_description_options, session_options,
1553 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001554 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001555 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001556 return nullptr;
1557 }
1558 break;
1559 default:
1560 RTC_NOTREACHED();
1561 }
1562 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 }
1564
1565 // Bundle the contents together, if we've been asked to do so, and update any
1566 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001567 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001569 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001570 if (content.rejected) {
1571 continue;
1572 }
zhihuang1c378ed2017-08-17 14:10:50 -07001573 // TODO(deadbeef): There are conditions that make bundling two media
1574 // descriptions together illegal. For example, they use the same payload
1575 // type to represent different codecs, or same IDs for different header
1576 // extensions. We need to detect this and not try to bundle those media
1577 // descriptions together.
1578 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579 }
Steve Anton2bed3972019-01-04 17:04:30 -08001580 if (!offer_bundle.content_names().empty()) {
1581 offer->AddGroup(offer_bundle);
1582 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1583 RTC_LOG(LS_ERROR)
1584 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1585 return nullptr;
1586 }
1587 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1588 RTC_LOG(LS_ERROR)
1589 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1590 return nullptr;
1591 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001592 }
1593 }
Steve Antone831b8c2018-02-01 12:22:16 -08001594
1595 // The following determines how to signal MSIDs to ensure compatibility with
1596 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001597 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001598 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1599 // Plan answerers will look at a=msid and Plan B answerers will look at the
1600 // a=ssrc MSID line.
1601 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1602 cricket::kMsidSignalingSsrcAttribute);
1603 } else {
1604 // Plan B always signals MSID using a=ssrc lines.
1605 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1606 }
1607
Johannes Kron89f874e2018-11-12 10:25:48 +01001608 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1609
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001610 if (session_options.media_transport_settings.has_value()) {
1611 offer->AddMediaTransportSetting(
1612 session_options.media_transport_settings->transport_name,
1613 session_options.media_transport_settings->transport_setting);
1614 }
1615
Steve Anton6fe1fba2018-12-11 10:15:23 -08001616 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617}
1618
Steve Anton6fe1fba2018-12-11 10:15:23 -08001619std::unique_ptr<SessionDescription>
1620MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001621 const SessionDescription* offer,
1622 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001624 if (!offer) {
1625 return nullptr;
1626 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001627
Steve Anton5c72e712018-12-10 14:25:30 -08001628 // Must have options for exactly as many sections as in the offer.
1629 RTC_DCHECK_EQ(offer->contents().size(),
1630 session_options.media_description_options.size());
1631
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001632 IceCredentialsIterator ice_credentials(
1633 session_options.pooled_ice_credentials);
1634
Steve Anton5c72e712018-12-10 14:25:30 -08001635 std::vector<const ContentInfo*> current_active_contents;
1636 if (current_description) {
1637 current_active_contents =
1638 GetActiveContents(*current_description, session_options);
1639 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
Steve Anton5c72e712018-12-10 14:25:30 -08001641 StreamParamsVec current_streams =
1642 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001643
zhihuang1c378ed2017-08-17 14:10:50 -07001644 // Get list of all possible codecs that respects existing payload type
1645 // mappings and uses a single payload type space.
1646 //
1647 // Note that these lists may be further filtered for each m= section; this
1648 // step is done just to establish the payload type mappings shared by all
1649 // sections.
1650 AudioCodecs answer_audio_codecs;
1651 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001652 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001653 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001654 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001655
1656 if (!session_options.vad_enabled) {
1657 // If application doesn't want CN codecs in answer.
1658 StripCNCodecs(&answer_audio_codecs);
1659 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001660 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001661 session_options.data_channel_type == DCT_SCTP);
1662
Steve Anton5c72e712018-12-10 14:25:30 -08001663 auto answer = absl::make_unique<SessionDescription>();
1664
1665 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1666 // group in the answer with the appropriate content names.
1667 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1668 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1669 // Transport info shared by the bundle group.
1670 std::unique_ptr<TransportInfo> bundle_transport;
1671
1672 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1673
zhihuang1c378ed2017-08-17 14:10:50 -07001674 // Iterate through the media description options, matching with existing
1675 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001676 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001677 for (const MediaDescriptionOptions& media_description_options :
1678 session_options.media_description_options) {
1679 const ContentInfo* offer_content = &offer->contents()[msection_index];
1680 // Media types and MIDs must match between the remote offer and the
1681 // MediaDescriptionOptions.
1682 RTC_DCHECK(
1683 IsMediaContentOfType(offer_content, media_description_options.type));
1684 RTC_DCHECK(media_description_options.mid == offer_content->name);
1685 const ContentInfo* current_content = nullptr;
1686 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001687 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001688 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001689 }
zhihuang1c378ed2017-08-17 14:10:50 -07001690 switch (media_description_options.type) {
1691 case MEDIA_TYPE_AUDIO:
1692 if (!AddAudioContentForAnswer(
1693 media_description_options, session_options, offer_content,
1694 offer, current_content, current_description,
1695 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001696 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001697 return nullptr;
1698 }
1699 break;
1700 case MEDIA_TYPE_VIDEO:
1701 if (!AddVideoContentForAnswer(
1702 media_description_options, session_options, offer_content,
1703 offer, current_content, current_description,
1704 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001705 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001706 return nullptr;
1707 }
1708 break;
1709 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001710 if (!AddDataContentForAnswer(
1711 media_description_options, session_options, offer_content,
1712 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001713 bundle_transport.get(), answer_rtp_data_codecs,
1714 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001715 return nullptr;
1716 }
1717 break;
1718 default:
1719 RTC_NOTREACHED();
1720 }
1721 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001722 // See if we can add the newly generated m= section to the BUNDLE group in
1723 // the answer.
1724 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001725 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001726 offer_bundle->HasContentName(added.name)) {
1727 answer_bundle.AddContentName(added.name);
1728 bundle_transport.reset(
1729 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 }
1732
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001733 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1734 // it's empty. RFC5888 says:
1735 //
1736 // A SIP entity that receives an offer that contains an "a=group" line
1737 // with semantics that are understood MUST return an answer that
1738 // contains an "a=group" line with the same semantics.
1739 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001740 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001741 }
deadbeefb7892532017-02-22 19:35:18 -08001742
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001743 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001744 // Share the same ICE credentials and crypto params across all contents,
1745 // as BUNDLE requires.
1746 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001747 RTC_LOG(LS_ERROR)
1748 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001749 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001750 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751
deadbeefb7892532017-02-22 19:35:18 -08001752 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001753 RTC_LOG(LS_ERROR)
1754 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001755 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756 }
1757 }
1758
Steve Antone831b8c2018-02-01 12:22:16 -08001759 // The following determines how to signal MSIDs to ensure compatibility with
1760 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001761 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001762 // Unified Plan needs to look at what the offer included to find the most
1763 // compatible answer.
1764 if (offer->msid_signaling() == 0) {
1765 // We end up here in one of three cases:
1766 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1767 // matter what we pick here.
1768 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1769 // it also doesn't matter what we pick here.
1770 // 3. Media that's either sendonly or inactive from the remote endpoint.
1771 // We don't have any information to say whether the endpoint is Plan B
1772 // or Unified Plan, so be conservative and send both.
1773 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1774 cricket::kMsidSignalingSsrcAttribute);
1775 } else if (offer->msid_signaling() ==
1776 (cricket::kMsidSignalingMediaSection |
1777 cricket::kMsidSignalingSsrcAttribute)) {
1778 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1779 // probably talking to a Unified Plan endpoint so respond with just
1780 // a=msid.
1781 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1782 } else {
1783 // Otherwise, it's clear which method the offerer is using so repeat that
1784 // back to them.
1785 answer->set_msid_signaling(offer->msid_signaling());
1786 }
1787 } else {
1788 // Plan B always signals MSID using a=ssrc lines.
1789 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1790 }
1791
Steve Anton6fe1fba2018-12-11 10:15:23 -08001792 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001793}
1794
ossu075af922016-06-14 03:29:38 -07001795const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1796 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001797 switch (direction) {
1798 // If stream is inactive - generate list as if sendrecv.
1799 case RtpTransceiverDirection::kSendRecv:
1800 case RtpTransceiverDirection::kInactive:
1801 return audio_sendrecv_codecs_;
1802 case RtpTransceiverDirection::kSendOnly:
1803 return audio_send_codecs_;
1804 case RtpTransceiverDirection::kRecvOnly:
1805 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001806 }
Steve Anton1d03a752017-11-27 14:30:09 -08001807 RTC_NOTREACHED();
1808 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001809}
1810
1811const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1812 const RtpTransceiverDirection& offer,
1813 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001814 switch (answer) {
1815 // For inactive and sendrecv answers, generate lists as if we were to accept
1816 // the offer's direction. See RFC 3264 Section 6.1.
1817 case RtpTransceiverDirection::kSendRecv:
1818 case RtpTransceiverDirection::kInactive:
1819 return GetAudioCodecsForOffer(
1820 webrtc::RtpTransceiverDirectionReversed(offer));
1821 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001822 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001823 case RtpTransceiverDirection::kRecvOnly:
1824 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001825 }
Steve Anton1d03a752017-11-27 14:30:09 -08001826 RTC_NOTREACHED();
1827 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001828}
1829
Steve Anton5c72e712018-12-10 14:25:30 -08001830void MergeCodecsFromDescription(
1831 const std::vector<const ContentInfo*>& current_active_contents,
1832 AudioCodecs* audio_codecs,
1833 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001834 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001835 UsedPayloadTypes* used_pltypes) {
1836 for (const ContentInfo* content : current_active_contents) {
1837 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001838 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001839 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001840 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001841 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001842 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001843 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001844 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001845 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001846 const RtpDataContentDescription* data =
1847 content->media_description()->as_rtp_data();
1848 if (data) {
1849 // Only relevant for RTP datachannels
1850 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1851 used_pltypes);
1852 }
zhihuang1c378ed2017-08-17 14:10:50 -07001853 }
1854 }
1855}
1856
1857// Getting codecs for an offer involves these steps:
1858//
1859// 1. Construct payload type -> codec mappings for current description.
1860// 2. Add any reference codecs that weren't already present
1861// 3. For each individual media description (m= section), filter codecs based
1862// on the directional attribute (happens in another method).
1863void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001864 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865 AudioCodecs* audio_codecs,
1866 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001867 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001869 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1870 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001871 UsedPayloadTypes used_pltypes;
1872 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001873 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874
Steve Anton5c72e712018-12-10 14:25:30 -08001875 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001876 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1877 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001878 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001879}
1880
1881// Getting codecs for an answer involves these steps:
1882//
1883// 1. Construct payload type -> codec mappings for current description.
1884// 2. Add any codecs from the offer that weren't already present.
1885// 3. Add any remaining codecs that weren't already present.
1886// 4. For each individual media description (m= section), filter codecs based
1887// on the directional attribute (happens in another method).
1888void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001889 const std::vector<const ContentInfo*>& current_active_contents,
1890 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001891 AudioCodecs* audio_codecs,
1892 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001893 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001894 // First - get all codecs from the current description if the media type
1895 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1896 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001897 UsedPayloadTypes used_pltypes;
1898 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001899 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001900
1901 // Second - filter out codecs that we don't support at all and should ignore.
1902 AudioCodecs filtered_offered_audio_codecs;
1903 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001904 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001905 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001906 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1907 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001908 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001909 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1910 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1911 filtered_offered_audio_codecs,
1912 offered_audio_codec, nullptr) &&
1913 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1914 offered_audio_codec, nullptr)) {
1915 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1916 }
1917 }
1918 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1919 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001920 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001921 for (const VideoCodec& offered_video_codec : video->codecs()) {
1922 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1923 filtered_offered_video_codecs,
1924 offered_video_codec, nullptr) &&
1925 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1926 offered_video_codec, nullptr)) {
1927 filtered_offered_video_codecs.push_back(offered_video_codec);
1928 }
1929 }
1930 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001931 const RtpDataContentDescription* data =
1932 content.media_description()->as_rtp_data();
1933 if (data) {
1934 // RTP data. This part is inactive for SCTP data.
1935 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1936 if (!FindMatchingCodec<RtpDataCodec>(
1937 data->codecs(), filtered_offered_rtp_data_codecs,
1938 offered_rtp_data_codec, nullptr) &&
1939 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1940 offered_rtp_data_codec,
1941 nullptr)) {
1942 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1943 }
zhihuang1c378ed2017-08-17 14:10:50 -07001944 }
1945 }
1946 }
1947 }
1948
Steve Anton5c72e712018-12-10 14:25:30 -08001949 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001950 // |remote_offer|.
1951 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1952 &used_pltypes);
1953 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1954 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001955 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001956 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001957}
1958
1959void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001960 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001961 RtpHeaderExtensions* offer_audio_extensions,
1962 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001963 // All header extensions allocated from the same range to avoid potential
1964 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001966 RtpHeaderExtensions all_regular_extensions;
1967 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968
1969 // First - get all extensions from the current description if the media type
1970 // is used.
1971 // Add them to |used_ids| so the local ids are not reused if a new media
1972 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001973 for (const ContentInfo* content : current_active_contents) {
1974 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1975 const AudioContentDescription* audio =
1976 content->media_description()->as_audio();
1977 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1978 &all_regular_extensions, &all_encrypted_extensions,
1979 &used_ids);
1980 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1981 const VideoContentDescription* video =
1982 content->media_description()->as_video();
1983 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1984 &all_regular_extensions, &all_encrypted_extensions,
1985 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001986 }
1987 }
1988
Steve Anton5c72e712018-12-10 14:25:30 -08001989 // Add our default RTP header extensions that are not in the current
1990 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001991 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1992 &all_regular_extensions, &all_encrypted_extensions,
1993 &used_ids);
1994 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1995 &all_regular_extensions, &all_encrypted_extensions,
1996 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001997
jbauch5869f502017-06-29 12:31:36 -07001998 // TODO(jbauch): Support adding encrypted header extensions to existing
1999 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08002000 if (enable_encrypted_rtp_header_extensions_ &&
2001 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07002002 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
2003 &all_encrypted_extensions, &used_ids);
2004 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
2005 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07002006 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007}
2008
2009bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02002010 const std::string& content_name,
2011 const TransportOptions& transport_options,
2012 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002013 SessionDescription* offer_desc,
2014 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002015 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02002016 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017 const TransportDescription* current_tdesc =
2018 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08002019 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002020 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
2021 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08002022 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002023 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
2024 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 }
Steve Anton06817cd2018-12-18 15:55:30 -08002026 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
2027 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028}
2029
Steve Anton1a9d3c32018-12-10 17:18:54 -08002030std::unique_ptr<TransportDescription>
2031MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032 const std::string& content_name,
2033 const SessionDescription* offer_desc,
2034 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002035 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002036 bool require_transport_attributes,
2037 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038 if (!transport_desc_factory_)
2039 return NULL;
2040 const TransportDescription* offer_tdesc =
2041 GetTransportDescription(content_name, offer_desc);
2042 const TransportDescription* current_tdesc =
2043 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08002044 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
2045 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002046 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047}
2048
2049bool MediaSessionDescriptionFactory::AddTransportAnswer(
2050 const std::string& content_name,
2051 const TransportDescription& transport_desc,
2052 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08002053 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054 return true;
2055}
2056
zhihuang1c378ed2017-08-17 14:10:50 -07002057// |audio_codecs| = set of all possible codecs that can be used, with correct
2058// payload type mappings
2059//
2060// |supported_audio_codecs| = set of codecs that are supported for the direction
2061// of this m= section
2062//
2063// acd->codecs() = set of previously negotiated codecs for this m= section
2064//
2065// The payload types should come from audio_codecs, but the order should come
2066// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2067// change existing codec priority, and that new codecs are added with the right
2068// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002069bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002070 const MediaDescriptionOptions& media_description_options,
2071 const MediaSessionOptions& session_options,
2072 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002073 const SessionDescription* current_description,
2074 const RtpHeaderExtensions& audio_rtp_extensions,
2075 const AudioCodecs& audio_codecs,
2076 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002077 SessionDescription* desc,
2078 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002079 // Filter audio_codecs (which includes all codecs, with correctly remapped
2080 // payload types) based on transceiver direction.
2081 const AudioCodecs& supported_audio_codecs =
2082 GetAudioCodecsForOffer(media_description_options.direction);
2083
2084 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002085
2086 if (!media_description_options.codec_preferences.empty()) {
2087 // Add the codecs from the current transceiver's codec preferences.
2088 // They override any existing codecs from previous negotiations.
2089 filtered_codecs = MatchCodecPreference(
2090 media_description_options.codec_preferences, supported_audio_codecs);
2091 } else {
2092 // Add the codecs from current content if it exists and is not rejected nor
2093 // recycled.
2094 if (current_content && !current_content->rejected &&
2095 current_content->name == media_description_options.mid) {
2096 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2097 const AudioContentDescription* acd =
2098 current_content->media_description()->as_audio();
2099 for (const AudioCodec& codec : acd->codecs()) {
2100 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2101 nullptr)) {
2102 filtered_codecs.push_back(codec);
2103 }
zhihuang1c378ed2017-08-17 14:10:50 -07002104 }
2105 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002106 // Add other supported audio codecs.
2107 AudioCodec found_codec;
2108 for (const AudioCodec& codec : supported_audio_codecs) {
2109 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2110 codec, &found_codec) &&
2111 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2112 filtered_codecs, codec, nullptr)) {
2113 // Use the |found_codec| from |audio_codecs| because it has the
2114 // correctly mapped payload type.
2115 filtered_codecs.push_back(found_codec);
2116 }
zhihuang1c378ed2017-08-17 14:10:50 -07002117 }
2118 }
deadbeef44f08192015-12-15 16:20:09 -08002119
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002120 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002121 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2122 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002123
kwiberg31022942016-03-11 14:18:21 -08002124 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002125 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002126 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2127 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002128 if (!CreateMediaContentOffer(media_description_options, session_options,
2129 filtered_codecs, sdes_policy,
2130 GetCryptos(current_content), crypto_suites,
2131 audio_rtp_extensions, ssrc_generator_,
2132 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002133 return false;
2134 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002135
2136 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2137 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002138
Steve Anton4e70a722017-11-28 14:57:10 -08002139 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002140
Steve Anton5adfafd2017-12-20 16:34:00 -08002141 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002142 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002143 if (!AddTransportOffer(media_description_options.mid,
2144 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002145 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002146 return false;
2147 }
2148
2149 return true;
2150}
2151
2152bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002153 const MediaDescriptionOptions& media_description_options,
2154 const MediaSessionOptions& session_options,
2155 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002156 const SessionDescription* current_description,
2157 const RtpHeaderExtensions& video_rtp_extensions,
2158 const VideoCodecs& video_codecs,
2159 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002160 SessionDescription* desc,
2161 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002162 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002163 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2164 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002165
kwiberg31022942016-03-11 14:18:21 -08002166 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002167 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002168 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2169 &crypto_suites);
2170
2171 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002172
2173 if (!media_description_options.codec_preferences.empty()) {
2174 // Add the codecs from the current transceiver's codec preferences.
2175 // They override any existing codecs from previous negotiations.
2176 filtered_codecs = MatchCodecPreference(
2177 media_description_options.codec_preferences, video_codecs_);
2178 } else {
2179 // Add the codecs from current content if it exists and is not rejected nor
2180 // recycled.
2181 if (current_content && !current_content->rejected &&
2182 current_content->name == media_description_options.mid) {
2183 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2184 const VideoContentDescription* vcd =
2185 current_content->media_description()->as_video();
2186 for (const VideoCodec& codec : vcd->codecs()) {
2187 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2188 nullptr)) {
2189 filtered_codecs.push_back(codec);
2190 }
zhihuang1c378ed2017-08-17 14:10:50 -07002191 }
2192 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002193 // Add other supported video codecs.
2194 VideoCodec found_codec;
2195 for (const VideoCodec& codec : video_codecs_) {
2196 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2197 &found_codec) &&
2198 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2199 nullptr)) {
2200 // Use the |found_codec| from |video_codecs| because it has the
2201 // correctly mapped payload type.
2202 filtered_codecs.push_back(found_codec);
2203 }
zhihuang1c378ed2017-08-17 14:10:50 -07002204 }
2205 }
2206
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002207 if (session_options.raw_packetization_for_video) {
2208 for (VideoCodec& codec : filtered_codecs) {
2209 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2210 codec.packetization = kPacketizationParamRaw;
2211 }
2212 }
2213 }
2214
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002215 if (!CreateMediaContentOffer(media_description_options, session_options,
2216 filtered_codecs, sdes_policy,
2217 GetCryptos(current_content), crypto_suites,
2218 video_rtp_extensions, ssrc_generator_,
2219 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002220 return false;
2221 }
2222
zhihuang1c378ed2017-08-17 14:10:50 -07002223 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002224
2225 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2226 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002227
Steve Anton4e70a722017-11-28 14:57:10 -08002228 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002229
Steve Anton5adfafd2017-12-20 16:34:00 -08002230 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002231 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002232 if (!AddTransportOffer(media_description_options.mid,
2233 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002234 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002235 return false;
2236 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002237 return true;
2238}
2239
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002240bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2241 const MediaDescriptionOptions& media_description_options,
2242 const MediaSessionOptions& session_options,
2243 const ContentInfo* current_content,
2244 const SessionDescription* current_description,
2245 StreamParamsVec* current_streams,
2246 SessionDescription* desc,
2247 IceCredentialsIterator* ice_credentials) const {
2248 std::unique_ptr<SctpDataContentDescription> data(
2249 new SctpDataContentDescription());
2250
2251 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2252
2253 cricket::SecurePolicy sdes_policy =
2254 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2255 : secure();
2256 std::vector<std::string> crypto_suites;
2257 // SDES doesn't make sense for SCTP, so we disable it, and we only
2258 // get SDES crypto suites for RTP-based data channels.
2259 sdes_policy = cricket::SEC_DISABLED;
2260 // Unlike SetMediaProtocol below, we need to set the protocol
2261 // before we call CreateMediaContentOffer. Otherwise,
2262 // CreateMediaContentOffer won't know this is SCTP and will
2263 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002264 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002265 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002266 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002267 data->set_max_message_size(kSctpSendBufferSize);
2268
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002269 if (!CreateContentOffer(media_description_options, session_options,
2270 sdes_policy, GetCryptos(current_content),
2271 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2272 current_streams, data.get())) {
2273 return false;
2274 }
2275
2276 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002277 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002278 if (!AddTransportOffer(media_description_options.mid,
2279 media_description_options.transport_options,
2280 current_description, desc, ice_credentials)) {
2281 return false;
2282 }
2283 return true;
2284}
2285
2286bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2287 const MediaDescriptionOptions& media_description_options,
2288 const MediaSessionOptions& session_options,
2289 const ContentInfo* current_content,
2290 const SessionDescription* current_description,
2291 const RtpDataCodecs& rtp_data_codecs,
2292 StreamParamsVec* current_streams,
2293 SessionDescription* desc,
2294 IceCredentialsIterator* ice_credentials) const {
2295 std::unique_ptr<RtpDataContentDescription> data(
2296 new RtpDataContentDescription());
2297 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2298
2299 cricket::SecurePolicy sdes_policy =
2300 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2301 : secure();
2302 std::vector<std::string> crypto_suites;
2303 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2304 &crypto_suites);
2305 if (!CreateMediaContentOffer(media_description_options, session_options,
2306 rtp_data_codecs, sdes_policy,
2307 GetCryptos(current_content), crypto_suites,
2308 RtpHeaderExtensions(), ssrc_generator_,
2309 current_streams, data.get())) {
2310 return false;
2311 }
2312
2313 data->set_bandwidth(kDataMaxBandwidth);
2314 SetMediaProtocol(secure_transport, data.get());
2315 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002316 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002317 if (!AddTransportOffer(media_description_options.mid,
2318 media_description_options.transport_options,
2319 current_description, desc, ice_credentials)) {
2320 return false;
2321 }
2322 return true;
2323}
2324
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002325bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002326 const MediaDescriptionOptions& media_description_options,
2327 const MediaSessionOptions& session_options,
2328 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002329 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002330 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002331 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002332 SessionDescription* desc,
2333 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002334 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2335 // If the DataChannel type is not specified, use the DataChannel type in
2336 // the current description.
2337 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002338 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002339 is_sctp = (current_content->media_description()->protocol() ==
2340 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002341 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002342 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002343 return AddSctpDataContentForOffer(
2344 media_description_options, session_options, current_content,
2345 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002346 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002347 return AddRtpDataContentForOffer(media_description_options, session_options,
2348 current_content, current_description,
2349 rtp_data_codecs, current_streams, desc,
2350 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002351 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002352}
2353
zhihuang1c378ed2017-08-17 14:10:50 -07002354// |audio_codecs| = set of all possible codecs that can be used, with correct
2355// payload type mappings
2356//
2357// |supported_audio_codecs| = set of codecs that are supported for the direction
2358// of this m= section
2359//
2360// acd->codecs() = set of previously negotiated codecs for this m= section
2361//
2362// The payload types should come from audio_codecs, but the order should come
2363// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2364// change existing codec priority, and that new codecs are added with the right
2365// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002366bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002367 const MediaDescriptionOptions& media_description_options,
2368 const MediaSessionOptions& session_options,
2369 const ContentInfo* offer_content,
2370 const SessionDescription* offer_description,
2371 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002372 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002373 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002374 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002375 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002376 SessionDescription* answer,
2377 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002378 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002379 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002380 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002381
Steve Anton1a9d3c32018-12-10 17:18:54 -08002382 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002383 media_description_options.mid, offer_description,
2384 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002385 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002386 if (!audio_transport) {
2387 return false;
2388 }
2389
zhihuang1c378ed2017-08-17 14:10:50 -07002390 // Pick codecs based on the requested communications direction in the offer
2391 // and the selected direction in the answer.
2392 // Note these will be filtered one final time in CreateMediaContentAnswer.
2393 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002394 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002395 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002396 AudioCodecs supported_audio_codecs =
2397 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2398
2399 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002400
2401 if (!media_description_options.codec_preferences.empty()) {
2402 filtered_codecs = MatchCodecPreference(
2403 media_description_options.codec_preferences, supported_audio_codecs);
2404 } else {
2405 // Add the codecs from current content if it exists and is not rejected nor
2406 // recycled.
2407 if (current_content && !current_content->rejected &&
2408 current_content->name == media_description_options.mid) {
2409 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2410 const AudioContentDescription* acd =
2411 current_content->media_description()->as_audio();
2412 for (const AudioCodec& codec : acd->codecs()) {
2413 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2414 nullptr)) {
2415 filtered_codecs.push_back(codec);
2416 }
zhihuang1c378ed2017-08-17 14:10:50 -07002417 }
2418 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002419 // Add other supported audio codecs.
2420 for (const AudioCodec& codec : supported_audio_codecs) {
2421 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2422 codec, nullptr) &&
2423 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2424 filtered_codecs, codec, nullptr)) {
2425 // We should use the local codec with local parameters and the codec id
2426 // would be correctly mapped in |NegotiateCodecs|.
2427 filtered_codecs.push_back(codec);
2428 }
zhihuang1c378ed2017-08-17 14:10:50 -07002429 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002430 }
2431
zhihuang1c378ed2017-08-17 14:10:50 -07002432 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2433 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002434 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002435 new AudioContentDescription());
2436 // Do not require or create SDES cryptos if DTLS is used.
2437 cricket::SecurePolicy sdes_policy =
2438 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002439 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2440 media_description_options, session_options,
2441 ssrc_generator_, current_streams,
2442 audio_answer.get())) {
2443 return false;
2444 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002445 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002446 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002447 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002448 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002449 enable_encrypted_rtp_header_extensions_, current_streams,
2450 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002451 return false; // Fails the session setup.
2452 }
2453
deadbeefb7892532017-02-22 19:35:18 -08002454 bool secure = bundle_transport ? bundle_transport->description.secure()
2455 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002456 bool rejected = media_description_options.stopped ||
2457 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002458 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2459 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002460 if (!AddTransportAnswer(media_description_options.mid,
2461 *(audio_transport.get()), answer)) {
2462 return false;
2463 }
2464
2465 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002466 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2467 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002468 }
2469
zhihuang1c378ed2017-08-17 14:10:50 -07002470 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002471 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002472 return true;
2473}
2474
2475bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002476 const MediaDescriptionOptions& media_description_options,
2477 const MediaSessionOptions& session_options,
2478 const ContentInfo* offer_content,
2479 const SessionDescription* offer_description,
2480 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002481 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002482 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002483 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002484 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002485 SessionDescription* answer,
2486 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002487 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002488 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002489 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002490
Steve Anton1a9d3c32018-12-10 17:18:54 -08002491 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002492 media_description_options.mid, offer_description,
2493 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002494 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002495 if (!video_transport) {
2496 return false;
2497 }
2498
zhihuang1c378ed2017-08-17 14:10:50 -07002499 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002500
2501 if (!media_description_options.codec_preferences.empty()) {
2502 filtered_codecs = MatchCodecPreference(
2503 media_description_options.codec_preferences, video_codecs_);
2504 } else {
2505 // Add the codecs from current content if it exists and is not rejected nor
2506 // recycled.
2507 if (current_content && !current_content->rejected &&
2508 current_content->name == media_description_options.mid) {
2509 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2510 const VideoContentDescription* vcd =
2511 current_content->media_description()->as_video();
2512 for (const VideoCodec& codec : vcd->codecs()) {
2513 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2514 nullptr)) {
2515 filtered_codecs.push_back(codec);
2516 }
zhihuang1c378ed2017-08-17 14:10:50 -07002517 }
2518 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002519 // Add other supported video codecs.
2520 for (const VideoCodec& codec : video_codecs_) {
2521 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2522 nullptr) &&
2523 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2524 nullptr)) {
2525 // We should use the local codec with local parameters and the codec id
2526 // would be correctly mapped in |NegotiateCodecs|.
2527 filtered_codecs.push_back(codec);
2528 }
zhihuang1c378ed2017-08-17 14:10:50 -07002529 }
2530 }
2531
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002532 if (session_options.raw_packetization_for_video) {
2533 for (VideoCodec& codec : filtered_codecs) {
2534 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2535 codec.packetization = kPacketizationParamRaw;
2536 }
2537 }
2538 }
2539
zhihuang1c378ed2017-08-17 14:10:50 -07002540 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2541 session_options.bundle_enabled;
2542
kwiberg31022942016-03-11 14:18:21 -08002543 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002544 new VideoContentDescription());
2545 // Do not require or create SDES cryptos if DTLS is used.
2546 cricket::SecurePolicy sdes_policy =
2547 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002548 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2549 media_description_options, session_options,
2550 ssrc_generator_, current_streams,
2551 video_answer.get())) {
2552 return false;
2553 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002554 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002555 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002556 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002557 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002558 enable_encrypted_rtp_header_extensions_, current_streams,
2559 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002560 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002561 }
deadbeefb7892532017-02-22 19:35:18 -08002562 bool secure = bundle_transport ? bundle_transport->description.secure()
2563 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002564 bool rejected = media_description_options.stopped ||
2565 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002566 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2567 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002568 if (!AddTransportAnswer(media_description_options.mid,
2569 *(video_transport.get()), answer)) {
2570 return false;
2571 }
2572
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002573 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002574 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002575 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002576 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2577 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002578 }
zhihuang1c378ed2017-08-17 14:10:50 -07002579 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002580 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002581 return true;
2582}
2583
2584bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002585 const MediaDescriptionOptions& media_description_options,
2586 const MediaSessionOptions& session_options,
2587 const ContentInfo* offer_content,
2588 const SessionDescription* offer_description,
2589 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002590 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002591 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002592 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002593 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002594 SessionDescription* answer,
2595 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002596 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002597 media_description_options.mid, offer_description,
2598 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002599 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002600 if (!data_transport) {
2601 return false;
2602 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002603
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002604 // Do not require or create SDES cryptos if DTLS is used.
2605 cricket::SecurePolicy sdes_policy =
2606 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002607 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2608 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002609 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002610 std::unique_ptr<MediaContentDescription> data_answer;
2611 if (offer_content->media_description()->as_sctp()) {
2612 // SCTP data content
2613 data_answer = absl::make_unique<SctpDataContentDescription>();
2614 const SctpDataContentDescription* offer_data_description =
2615 offer_content->media_description()->as_sctp();
2616 // Respond with the offerer's proto, whatever it is.
2617 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002618 // Respond with our max message size or the remote max messsage size,
2619 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002620 // 0 is treated specially - it means "I can accept any size". Since
2621 // we do not implement infinite size messages, reply with
2622 // kSctpSendBufferSize.
2623 if (offer_data_description->max_message_size() == 0) {
2624 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2625 } else {
2626 data_answer->as_sctp()->set_max_message_size(std::min(
2627 offer_data_description->max_message_size(), kSctpSendBufferSize));
2628 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002629 if (!CreateMediaContentAnswer(
2630 offer_data_description, media_description_options, session_options,
2631 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2632 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2633 current_streams, bundle_enabled, data_answer.get())) {
2634 return false; // Fails the session setup.
2635 }
2636 // Respond with sctpmap if the offer uses sctpmap.
2637 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2638 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2639 } else {
2640 // RTP offer
2641 data_answer = absl::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002642
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002643 const RtpDataContentDescription* offer_data_description =
2644 offer_content->media_description()->as_rtp_data();
2645 RTC_CHECK(offer_data_description);
2646 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2647 media_description_options, session_options,
2648 ssrc_generator_, current_streams,
2649 data_answer->as_rtp_data())) {
2650 return false;
2651 }
2652 if (!CreateMediaContentAnswer(
2653 offer_data_description, media_description_options, session_options,
2654 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2655 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2656 current_streams, bundle_enabled, data_answer.get())) {
2657 return false; // Fails the session setup.
2658 }
2659 }
Steve Anton46afbf92019-05-10 11:15:18 -07002660
deadbeefb7892532017-02-22 19:35:18 -08002661 bool secure = bundle_transport ? bundle_transport->description.secure()
2662 : data_transport->secure();
2663
zhihuang1c378ed2017-08-17 14:10:50 -07002664 bool rejected = session_options.data_channel_type == DCT_NONE ||
2665 media_description_options.stopped ||
2666 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002667 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2668 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002669 if (!AddTransportAnswer(media_description_options.mid,
2670 *(data_transport.get()), answer)) {
2671 return false;
2672 }
2673
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002674 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002675 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002676 } else {
2677 // RFC 3264
2678 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002679 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002680 }
zhihuang1c378ed2017-08-17 14:10:50 -07002681 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002682 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002683 return true;
2684}
2685
zhihuang1c378ed2017-08-17 14:10:50 -07002686void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2687 audio_sendrecv_codecs_.clear();
2688 all_audio_codecs_.clear();
2689 // Compute the audio codecs union.
2690 for (const AudioCodec& send : audio_send_codecs_) {
2691 all_audio_codecs_.push_back(send);
2692 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2693 send, nullptr)) {
2694 // It doesn't make sense to have an RTX codec we support sending but not
2695 // receiving.
2696 RTC_DCHECK(!IsRtxCodec(send));
2697 }
2698 }
2699 for (const AudioCodec& recv : audio_recv_codecs_) {
2700 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2701 recv, nullptr)) {
2702 all_audio_codecs_.push_back(recv);
2703 }
2704 }
2705 // Use NegotiateCodecs to merge our codec lists, since the operation is
2706 // essentially the same. Put send_codecs as the offered_codecs, which is the
2707 // order we'd like to follow. The reasoning is that encoding is usually more
2708 // expensive than decoding, and prioritizing a codec in the send list probably
2709 // means it's a codec we can handle efficiently.
2710 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002711 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002712}
2713
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002715 return (content && (content->type == MediaProtocolType::kRtp ||
2716 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002717}
2718
2719bool IsAudioContent(const ContentInfo* content) {
2720 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2721}
2722
2723bool IsVideoContent(const ContentInfo* content) {
2724 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2725}
2726
2727bool IsDataContent(const ContentInfo* content) {
2728 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2729}
2730
deadbeef0ed85b22016-02-23 17:24:52 -08002731const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2732 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002733 for (const ContentInfo& content : contents) {
2734 if (IsMediaContentOfType(&content, media_type)) {
2735 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736 }
2737 }
deadbeef0ed85b22016-02-23 17:24:52 -08002738 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002739}
2740
2741const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2742 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2743}
2744
2745const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2746 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2747}
2748
2749const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2750 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2751}
2752
Steve Antonad7bffc2018-01-22 10:21:56 -08002753const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2754 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002755 if (sdesc == nullptr) {
2756 return nullptr;
2757 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758
2759 return GetFirstMediaContent(sdesc->contents(), media_type);
2760}
2761
2762const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2763 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2764}
2765
2766const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2767 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2768}
2769
2770const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2771 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2772}
2773
2774const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002775 const SessionDescription* sdesc,
2776 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002778 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779}
2780
2781const AudioContentDescription* GetFirstAudioContentDescription(
2782 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002783 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2784 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002785}
2786
2787const VideoContentDescription* GetFirstVideoContentDescription(
2788 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002789 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2790 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791}
2792
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002793const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2794 const SessionDescription* sdesc) {
2795 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2796 return desc ? desc->as_rtp_data() : nullptr;
2797}
2798
2799const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2800 const SessionDescription* sdesc) {
2801 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2802 return desc ? desc->as_sctp() : nullptr;
2803}
2804
2805// Returns a shim representing either an SctpDataContentDescription
2806// or an RtpDataContentDescription, as appropriate.
2807// TODO(bugs.webrtc.org/10597): Remove together with shim.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808const DataContentDescription* GetFirstDataContentDescription(
2809 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002810 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2811 return desc ? desc->as_data() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002812}
2813
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002814//
2815// Non-const versions of the above functions.
2816//
2817
Steve Anton36b29d12017-10-30 09:57:42 -07002818ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002819 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002820 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002821 if (IsMediaContentOfType(&content, media_type)) {
2822 return &content;
2823 }
2824 }
2825 return nullptr;
2826}
2827
Steve Anton36b29d12017-10-30 09:57:42 -07002828ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002829 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2830}
2831
Steve Anton36b29d12017-10-30 09:57:42 -07002832ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002833 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2834}
2835
Steve Anton36b29d12017-10-30 09:57:42 -07002836ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002837 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2838}
2839
Steve Antonad7bffc2018-01-22 10:21:56 -08002840ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2841 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002842 if (sdesc == nullptr) {
2843 return nullptr;
2844 }
2845
Steve Anton36b29d12017-10-30 09:57:42 -07002846 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002847}
2848
2849ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2850 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2851}
2852
2853ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2854 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2855}
2856
2857ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2858 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2859}
2860
2861MediaContentDescription* GetFirstMediaContentDescription(
2862 SessionDescription* sdesc,
2863 MediaType media_type) {
2864 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002865 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002866}
2867
2868AudioContentDescription* GetFirstAudioContentDescription(
2869 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002870 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2871 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002872}
2873
2874VideoContentDescription* GetFirstVideoContentDescription(
2875 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002876 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2877 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002878}
2879
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002880RtpDataContentDescription* GetFirstRtpDataContentDescription(
2881 SessionDescription* sdesc) {
2882 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2883 return desc ? desc->as_rtp_data() : nullptr;
2884}
2885
2886SctpDataContentDescription* GetFirstSctpDataContentDescription(
2887 SessionDescription* sdesc) {
2888 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2889 return desc ? desc->as_sctp() : nullptr;
2890}
2891
2892// Returns shim
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002893DataContentDescription* GetFirstDataContentDescription(
2894 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002895 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2896 return desc ? desc->as_data() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002897}
2898
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002899} // namespace cricket