blob: e18c86a249f849b560bbafecb5c3bbf06d5ee256 [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
13#include <functional>
14#include <map>
kwiberg31022942016-03-11 14:18:21 -080015#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000016#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070017#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000018#include <utility>
19
Steve Anton64b626b2019-01-28 17:25:26 -080020#include "absl/algorithm/container.h"
Steve Anton5c72e712018-12-10 14:25:30 -080021#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020022#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020023#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "media/base/media_constants.h"
27#include "p2p/base/p2p_constants.h"
28#include "pc/channel_manager.h"
29#include "pc/rtp_media_utils.h"
30#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/checks.h"
32#include "rtc_base/helpers.h"
33#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020034#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080035#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
37namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080038
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080039using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080040using webrtc::RtpTransceiverDirection;
41
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080043
Benjamin Wrighta54daf12018-10-11 15:33:17 -070044void GetSupportedSdesCryptoSuiteNames(
45 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
46 const webrtc::CryptoOptions& crypto_options,
47 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080048 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070049 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080050 for (const auto crypto : crypto_suites) {
51 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
52 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080053}
terelius8c011e52016-04-26 05:28:11 -070054} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055
56namespace cricket {
57
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058// RTP Profile names
59// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
60// RFC4585
61const char kMediaProtocolAvpf[] = "RTP/AVPF";
62// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000063const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
64
deadbeeff3938292015-07-15 12:20:53 -070065// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
66// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067const char kMediaProtocolSavpf[] = "RTP/SAVPF";
68
69const char kMediaProtocolRtpPrefix[] = "RTP/";
70
71const char kMediaProtocolSctp[] = "SCTP";
72const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000073const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000074const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
deadbeef8b7e9ad2017-05-25 09:38:55 -070076// Note that the below functions support some protocol strings purely for
77// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
78// and Interoperability.
79
80static bool IsDtlsRtp(const std::string& protocol) {
81 // Most-likely values first.
82 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
83 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
84}
85
86static bool IsPlainRtp(const std::string& protocol) {
87 // Most-likely values first.
88 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
89 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
90}
91
92static bool IsDtlsSctp(const std::string& protocol) {
93 return protocol == kMediaProtocolDtlsSctp ||
94 protocol == kMediaProtocolUdpDtlsSctp ||
95 protocol == kMediaProtocolTcpDtlsSctp;
96}
97
98static bool IsPlainSctp(const std::string& protocol) {
99 return protocol == kMediaProtocolSctp;
100}
101
102static bool IsSctp(const std::string& protocol) {
103 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
104}
105
Steve Anton1d03a752017-11-27 14:30:09 -0800106static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
107 RtpTransceiverDirection offer,
108 RtpTransceiverDirection wants) {
109 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
110 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
111 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
112 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
113 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
114 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -0700115}
116
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117static bool IsMediaContentOfType(const ContentInfo* content,
118 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800119 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120 return false;
121 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800122 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123}
124
Yves Gerey665174f2018-06-19 15:03:05 +0200125static bool CreateCryptoParams(int tag,
126 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700127 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700128 int key_len;
129 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200130 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
131 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132 return false;
133 }
jbauchcb560652016-08-04 05:20:32 -0700134
135 int master_key_len = key_len + salt_len;
136 std::string master_key;
137 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
138 return false;
139 }
140
kwiberg352444f2016-11-28 15:58:53 -0800141 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700142 std::string key = rtc::Base64::Encode(master_key);
143
Steve Anton3a66edf2018-09-10 12:57:37 -0700144 crypto_out->tag = tag;
145 crypto_out->cipher_suite = cipher;
146 crypto_out->key_params = kInline;
147 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148 return true;
149}
150
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700152 CryptoParamsVec* cryptos_out) {
153 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154
Steve Anton3a66edf2018-09-10 12:57:37 -0700155 cryptos_out->resize(size + 1);
156 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157}
158
159void AddMediaCryptos(const CryptoParamsVec& cryptos,
160 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700161 for (const CryptoParams& crypto : cryptos) {
162 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163 }
164}
165
166bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
167 MediaContentDescription* media) {
168 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700169 for (const std::string& crypto_suite : crypto_suites) {
170 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171 return false;
172 }
173 }
174 AddMediaCryptos(cryptos, media);
175 return true;
176}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177
zhihuang1c378ed2017-08-17 14:10:50 -0700178const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800179 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700180 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000181 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800182 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183}
184
185bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
186 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700187 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800188 auto it = absl::c_find_if(
189 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700190 if (it == cryptos.end()) {
191 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700193 *crypto_out = *it;
194 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195}
196
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700197// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
198// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700199void GetSupportedAudioSdesCryptoSuites(
200 const webrtc::CryptoOptions& crypto_options,
201 std::vector<int>* crypto_suites) {
202 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700203 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
204 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
205 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700206 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700207 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
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 GetSupportedAudioSdesCryptoSuiteNames(
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(GetSupportedAudioSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedVideoSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227}
228
deadbeef7914b8c2017-04-21 03:23:33 -0700229void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800231 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700232 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
234}
235
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700236void GetSupportedDataSdesCryptoSuites(
237 const webrtc::CryptoOptions& crypto_options,
238 std::vector<int>* crypto_suites) {
239 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700240 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
241 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
242 }
243 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
244}
245
246void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700247 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700248 std::vector<std::string>* crypto_suite_names) {
249 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
250 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800251}
252
jbauchcb560652016-08-04 05:20:32 -0700253// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700254// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
255// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700256// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257static bool SelectCrypto(const MediaContentDescription* offer,
258 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700259 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700260 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
262 const CryptoParamsVec& cryptos = offer->cryptos();
263
Steve Anton3a66edf2018-09-10 12:57:37 -0700264 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700265 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700266 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
267 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
268 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700269 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700270 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 }
272 }
273 return false;
274}
275
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000276// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800277static StreamParamsVec GetCurrentStreamParams(
278 const std::vector<const ContentInfo*>& active_local_contents) {
279 StreamParamsVec stream_params;
280 for (const ContentInfo* content : active_local_contents) {
281 for (const StreamParams& params : content->media_description()->streams()) {
282 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 }
284 }
Steve Anton5c72e712018-12-10 14:25:30 -0800285 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286}
287
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000288// Filters the data codecs for the data channel type.
289void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
290 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700291 const char* codec_name =
292 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700293 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
294 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200295 return absl::EqualsIgnoreCase(codec.name,
296 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700297 }),
298 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000299}
300
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301template <typename IdStruct>
302class UsedIds {
303 public:
304 UsedIds(int min_allowed_id, int max_allowed_id)
305 : min_allowed_id_(min_allowed_id),
306 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200307 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000308
309 // Loops through all Id in |ids| and changes its id if it is
310 // already in use by another IdStruct. Call this methods with all Id
311 // in a session description to make sure no duplicate ids exists.
312 // Note that typename Id must be a type of IdStruct.
313 template <typename Id>
314 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700315 for (const Id& id : *ids) {
316 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317 }
318 }
319
320 // Finds and sets an unused id if the |idstruct| id is already in use.
321 void FindAndSetIdUsed(IdStruct* idstruct) {
322 const int original_id = idstruct->id;
323 int new_id = idstruct->id;
324
325 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
326 // If the original id is not in range - this is an id that can't be
327 // dynamically changed.
328 return;
329 }
330
331 if (IsIdUsed(original_id)) {
332 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100333 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
334 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335 idstruct->id = new_id;
336 }
337 SetIdUsed(new_id);
338 }
339
340 private:
341 // Returns the first unused id in reverse order.
342 // This hopefully reduce the risk of more collisions. We want to change the
343 // default ids as little as possible.
344 int FindUnusedId() {
345 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
346 --next_id_;
347 }
nisseede5da42017-01-12 05:15:36 -0800348 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 return next_id_;
350 }
351
Yves Gerey665174f2018-06-19 15:03:05 +0200352 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353
Yves Gerey665174f2018-06-19 15:03:05 +0200354 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355
356 const int min_allowed_id_;
357 const int max_allowed_id_;
358 int next_id_;
359 std::set<int> id_set_;
360};
361
362// Helper class used for finding duplicate RTP payload types among audio, video
363// and data codecs. When bundle is used the payload types may not collide.
364class UsedPayloadTypes : public UsedIds<Codec> {
365 public:
366 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200367 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
369 private:
370 static const int kDynamicPayloadTypeMin = 96;
371 static const int kDynamicPayloadTypeMax = 127;
372};
373
374// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200375// audio and video extensions. Only applies to one-byte header extensions at the
376// moment. ids > 14 will always be reported as available.
377// TODO(kron): This class needs to be refactored when we start to send two-byte
378// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700379class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000380 public:
381 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200382 : UsedIds<webrtc::RtpExtension>(
383 webrtc::RtpExtension::kMinId,
384 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385
386 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387};
388
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800389static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
390 const SenderOptions& sender,
391 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800392 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800393 bool include_flexfec_stream,
394 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800395 StreamParams result;
396 result.id = sender.track_id;
397
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800398 // TODO(brandtr): Update when we support multistream protection.
399 if (include_flexfec_stream && sender.num_sim_layers > 1) {
400 include_flexfec_stream = false;
401 RTC_LOG(LS_WARNING)
402 << "Our FlexFEC implementation only supports protecting "
403 "a single media streams. This session has multiple "
404 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800405 }
406
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800407 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
408 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800409
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 result.cname = rtcp_cname;
411 result.set_stream_ids(sender.stream_ids);
412
413 return result;
414}
415
416static bool ValidateSimulcastLayers(
417 const std::vector<RidDescription>& rids,
418 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800419 return absl::c_all_of(
420 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
421 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
422 return rid.rid == layer.rid;
423 });
424 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800425}
426
427static StreamParams CreateStreamParamsForNewSenderWithRids(
428 const SenderOptions& sender,
429 const std::string& rtcp_cname) {
430 RTC_DCHECK(!sender.rids.empty());
431 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
432 << "RIDs are the compliant way to indicate simulcast.";
433 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
434 StreamParams result;
435 result.id = sender.track_id;
436 result.cname = rtcp_cname;
437 result.set_stream_ids(sender.stream_ids);
438
439 // More than one rid should be signaled.
440 if (sender.rids.size() > 1) {
441 result.set_rids(sender.rids);
442 }
443
444 return result;
445}
446
447// Adds SimulcastDescription if indicated by the media description options.
448// MediaContentDescription should already be set up with the send rids.
449static void AddSimulcastToMediaDescription(
450 const MediaDescriptionOptions& media_description_options,
451 MediaContentDescription* description) {
452 RTC_DCHECK(description);
453
454 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800455 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
456 return !params.has_rids();
457 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800458 return;
459 }
460
461 RTC_DCHECK_EQ(1, description->streams().size())
462 << "RIDs are only supported in Unified Plan semantics.";
463 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
464 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
465 description->type() == MediaType::MEDIA_TYPE_VIDEO);
466
467 // One RID or less indicates that simulcast is not needed.
468 if (description->streams()[0].rids().size() <= 1) {
469 return;
470 }
471
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800472 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800473 SimulcastDescription simulcast;
474 simulcast.send_layers() =
475 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800476 description->set_simulcast_description(simulcast);
477}
478
zhihuang1c378ed2017-08-17 14:10:50 -0700479// Adds a StreamParams for each SenderOptions in |sender_options| to
480// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481// |current_params| - All currently known StreamParams of any media type.
482template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700483static bool AddStreamParams(
484 const std::vector<SenderOptions>& sender_options,
485 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800486 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700487 StreamParamsVec* current_streams,
488 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700489 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700490 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700491 return true;
492 }
493
Noah Richards2e7a0982015-05-18 14:02:54 -0700494 const bool include_rtx_streams =
495 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496
brandtr03d5fb12016-11-22 03:37:59 -0800497 const bool include_flexfec_stream =
498 ContainsFlexfecCodec(content_description->codecs());
499
zhihuang1c378ed2017-08-17 14:10:50 -0700500 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 // groupid is empty for StreamParams generated using
502 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700503 StreamParams* param =
504 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000505 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700506 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800507 StreamParams stream_param =
508 sender.rids.empty()
509 ?
510 // Signal SSRCs and legacy simulcast (if requested).
511 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800512 sender, rtcp_cname, include_rtx_streams,
513 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800514 :
515 // Signal RIDs and spec-compliant simulcast (if requested).
516 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
517
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 content_description->AddStream(stream_param);
519
520 // Store the new StreamParams in current_streams.
521 // This is necessary so that we can use the CNAME for other media types.
522 current_streams->push_back(stream_param);
523 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700524 // Use existing generated SSRCs/groups, but update the sync_label if
525 // necessary. This may be needed if a MediaStreamTrack was moved from one
526 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800527 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000528 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 }
530 }
531 return true;
532}
533
534// Updates the transport infos of the |sdesc| according to the given
535// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800536// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
537// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
539 SessionDescription* sdesc) {
540 // The bundle should not be empty.
541 if (!sdesc || !bundle_group.FirstContentName()) {
542 return false;
543 }
544
545 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700546 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 const TransportInfo* selected_transport_info =
548 sdesc->GetTransportInfoByName(selected_content_name);
549 if (!selected_transport_info) {
550 return false;
551 }
552
553 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700554 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700556 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800558 ConnectionRole selected_connection_role =
559 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700560 for (TransportInfo& transport_info : sdesc->transport_infos()) {
561 if (bundle_group.HasContentName(transport_info.content_name) &&
562 transport_info.content_name != selected_content_name) {
563 transport_info.description.ice_ufrag = selected_ufrag;
564 transport_info.description.ice_pwd = selected_pwd;
565 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 }
567 }
568 return true;
569}
570
571// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
572// sets it to |cryptos|.
573static bool GetCryptosByName(const SessionDescription* sdesc,
574 const std::string& content_name,
575 CryptoParamsVec* cryptos) {
576 if (!sdesc || !cryptos) {
577 return false;
578 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800580 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 return false;
582 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800583 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 return true;
585}
586
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
588// which are not available in |filter|.
589static void PruneCryptos(const CryptoParamsVec& filter,
590 CryptoParamsVec* target_cryptos) {
591 if (!target_cryptos) {
592 return;
593 }
tzik21995802018-04-26 17:38:28 +0900594
595 target_cryptos->erase(
596 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
597 // Returns true if the |crypto|'s cipher_suite is not
598 // found in |filter|.
599 [&filter](const CryptoParams& crypto) {
600 for (const CryptoParams& entry : filter) {
601 if (entry.cipher_suite == crypto.cipher_suite)
602 return false;
603 }
604 return true;
605 }),
606 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607}
608
Steve Antonfa2260d2017-12-28 16:38:23 -0800609bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800610 return protocol.empty() ||
611 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
612}
613
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614static bool IsRtpContent(SessionDescription* sdesc,
615 const std::string& content_name) {
616 bool is_rtp = false;
617 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800618 if (content && content->media_description()) {
619 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 }
621 return is_rtp;
622}
623
624// Updates the crypto parameters of the |sdesc| according to the given
625// |bundle_group|. The crypto parameters of all the contents within the
626// |bundle_group| should be updated to use the common subset of the
627// available cryptos.
628static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
629 SessionDescription* sdesc) {
630 // The bundle should not be empty.
631 if (!sdesc || !bundle_group.FirstContentName()) {
632 return false;
633 }
634
wu@webrtc.org78187522013-10-07 23:32:02 +0000635 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 // Get the common cryptos.
637 const ContentNames& content_names = bundle_group.content_names();
638 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700639 bool first = true;
640 for (const std::string& content_name : content_names) {
641 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 continue;
643 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000644 // The common cryptos are needed if any of the content does not have DTLS
645 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700646 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000647 common_cryptos_needed = true;
648 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700649 if (first) {
650 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700652 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 return false;
654 }
655 if (common_cryptos.empty()) {
656 // If there's no crypto params, we should just return.
657 return true;
658 }
659 } else {
660 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700661 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 return false;
663 }
664 PruneCryptos(cryptos, &common_cryptos);
665 }
666 }
667
wu@webrtc.org78187522013-10-07 23:32:02 +0000668 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 return false;
670 }
671
672 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700673 for (const std::string& content_name : content_names) {
674 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 continue;
676 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700677 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800679 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 if (!media_desc) {
681 return false;
682 }
683 media_desc->set_cryptos(common_cryptos);
684 }
685 }
686 return true;
687}
688
Steve Anton5c72e712018-12-10 14:25:30 -0800689static std::vector<const ContentInfo*> GetActiveContents(
690 const SessionDescription& description,
691 const MediaSessionOptions& session_options) {
692 std::vector<const ContentInfo*> active_contents;
693 for (size_t i = 0; i < description.contents().size(); ++i) {
694 RTC_DCHECK_LT(i, session_options.media_description_options.size());
695 const ContentInfo& content = description.contents()[i];
696 const MediaDescriptionOptions& media_options =
697 session_options.media_description_options[i];
698 if (!content.rejected && !media_options.stopped &&
699 content.name == media_options.mid) {
700 active_contents.push_back(&content);
701 }
702 }
703 return active_contents;
704}
705
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706template <class C>
707static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800708 for (const auto& codec : codecs) {
709 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 return true;
711 }
712 }
713 return false;
714}
715
716template <class C>
717static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200718 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000719}
720
brandtr03d5fb12016-11-22 03:37:59 -0800721template <class C>
722static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
723 for (const auto& codec : codecs) {
724 if (IsFlexfecCodec(codec)) {
725 return true;
726 }
727 }
728 return false;
729}
730
731template <class C>
732static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200733 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800734}
735
zhihuang1c378ed2017-08-17 14:10:50 -0700736// Create a media content to be offered for the given |sender_options|,
737// according to the given options.rtcp_mux, session_options.is_muc, codecs,
738// secure_transport, crypto, and current_streams. If we don't currently have
739// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
740// created (according to crypto_suites). The created content is added to the
741// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742template <class C>
743static bool CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800744 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700745 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000747 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 const CryptoParamsVec* current_cryptos,
749 const std::vector<std::string>& crypto_suites,
750 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800751 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 StreamParamsVec* current_streams,
753 MediaContentDescriptionImpl<C>* offer) {
754 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755
zhihuang1c378ed2017-08-17 14:10:50 -0700756 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700757 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
758 offer->set_rtcp_reduced_size(true);
759 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 offer->set_rtp_header_extensions(rtp_extensions);
761
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800762 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800763 session_options.rtcp_cname, ssrc_generator,
764 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765 return false;
766 }
767
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800768 AddSimulcastToMediaDescription(media_description_options, offer);
769
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 if (secure_policy != SEC_DISABLED) {
771 if (current_cryptos) {
772 AddMediaCryptos(*current_cryptos, offer);
773 }
774 if (offer->cryptos().empty()) {
775 if (!CreateMediaCryptos(crypto_suites, offer)) {
776 return false;
777 }
778 }
779 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780
deadbeef7af91dd2016-12-13 11:29:11 -0800781 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 return false;
783 }
784 return true;
785}
786
787template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000788static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800789 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000790 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800791 const int codec2_id) {
792 const C* codec1 = FindCodecById(codecs1, codec1_id);
793 const C* codec2 = FindCodecById(codecs2, codec2_id);
794 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000795}
796
797template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798static void NegotiateCodecs(const std::vector<C>& local_codecs,
799 const std::vector<C>& offered_codecs,
800 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800801 for (const C& ours : local_codecs) {
802 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700803 // Note that we intentionally only find one matching codec for each of our
804 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800805 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
806 C negotiated = ours;
807 negotiated.IntersectFeedbackParams(theirs);
808 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800809 const auto apt_it =
810 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800811 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800812 RTC_DCHECK(apt_it != theirs.params.end());
813 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 }
Niels Möller039743e2018-10-23 10:07:25 +0200815 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800816 webrtc::H264::GenerateProfileLevelIdForAnswer(
817 ours.params, theirs.params, &negotiated.params);
818 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800819 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700820 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800821 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 }
823 }
deadbeef67cf2c12016-04-13 10:07:16 -0700824 // RFC3264: Although the answerer MAY list the formats in their desired
825 // order of preference, it is RECOMMENDED that unless there is a
826 // specific reason, the answerer list formats in the same relative order
827 // they were present in the offer.
828 std::unordered_map<int, int> payload_type_preferences;
829 int preference = static_cast<int>(offered_codecs.size() + 1);
830 for (const C& codec : offered_codecs) {
831 payload_type_preferences[codec.id] = preference--;
832 }
Steve Anton64b626b2019-01-28 17:25:26 -0800833 absl::c_sort(
834 *negotiated_codecs, [&payload_type_preferences](const C& a, const C& b) {
835 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
836 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837}
838
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800839// Finds a codec in |codecs2| that matches |codec_to_match|, which is
840// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
841// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800843static bool FindMatchingCodec(const std::vector<C>& codecs1,
844 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 const C& codec_to_match,
846 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700847 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
848 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800849 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
850 return &codec == &codec_to_match;
851 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852 for (const C& potential_match : codecs2) {
853 if (potential_match.Matches(codec_to_match)) {
854 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800855 int apt_value_1 = 0;
856 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800857 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
858 &apt_value_1) ||
859 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
860 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100861 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800862 continue;
863 }
864 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
865 apt_value_2)) {
866 continue;
867 }
868 }
869 if (found_codec) {
870 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871 }
872 return true;
873 }
874 }
875 return false;
876}
877
zhihuang1c378ed2017-08-17 14:10:50 -0700878// Find the codec in |codec_list| that |rtx_codec| is associated with.
879template <class C>
880static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
881 const C& rtx_codec) {
882 std::string associated_pt_str;
883 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
884 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100885 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
886 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700887 return nullptr;
888 }
889
890 int associated_pt;
891 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100892 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
893 << " of RTX codec " << rtx_codec.name
894 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700895 return nullptr;
896 }
897
898 // Find the associated reference codec for the reference RTX codec.
899 const C* associated_codec = FindCodecById(codec_list, associated_pt);
900 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100901 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
902 << associated_pt << " for RTX codec " << rtx_codec.name
903 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700904 }
905 return associated_codec;
906}
907
908// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909// already exist in |offered_codecs| and ensure the payload types don't
910// collide.
911template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700912static void MergeCodecs(const std::vector<C>& reference_codecs,
913 std::vector<C>* offered_codecs,
914 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800916 for (const C& reference_codec : reference_codecs) {
917 if (!IsRtxCodec(reference_codec) &&
918 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
919 reference_codec, nullptr)) {
920 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000921 used_pltypes->FindAndSetIdUsed(&codec);
922 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 }
924 }
925
926 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800927 for (const C& reference_codec : reference_codecs) {
928 if (IsRtxCodec(reference_codec) &&
929 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
930 reference_codec, nullptr)) {
931 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700932 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700933 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700934 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700935 continue;
936 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800937 // Find a codec in the offered list that matches the reference codec.
938 // Its payload type may be different than the reference codec.
939 C matching_codec;
940 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800941 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100942 RTC_LOG(LS_WARNING)
943 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800944 continue;
945 }
946
947 rtx_codec.params[kCodecParamAssociatedPayloadType] =
948 rtc::ToString(matching_codec.id);
949 used_pltypes->FindAndSetIdUsed(&rtx_codec);
950 offered_codecs->push_back(rtx_codec);
951 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952 }
953}
954
zhihuang1c378ed2017-08-17 14:10:50 -0700955static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
956 const webrtc::RtpExtension& ext_to_match,
957 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800958 auto it = absl::c_find_if(
959 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
960 // We assume that all URIs are given in a canonical
961 // format.
962 return extension.uri == ext_to_match.uri &&
963 extension.encrypt == ext_to_match.encrypt;
964 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700965 if (it == extensions.end()) {
966 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700967 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700968 if (found_extension) {
969 *found_extension = *it;
970 }
971 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700972}
973
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700975 const webrtc::RtpExtension& ext_to_match,
976 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700977 // We assume that all URIs are given in a canonical format.
978 const webrtc::RtpExtension* found =
979 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
980 ext_to_match.uri);
981 if (!found) {
982 return false;
983 }
984 if (found_extension) {
985 *found_extension = *found;
986 }
987 return true;
988}
989
990static bool FindByUriWithEncryptionPreference(
991 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200992 const webrtc::RtpExtension& ext_to_match,
993 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700994 webrtc::RtpExtension* found_extension) {
995 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700996 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700998 if (extension.uri == ext_to_match.uri) {
999 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001000 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001001 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001002 }
1003 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001005 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001006 }
1007 }
jbauch5869f502017-06-29 12:31:36 -07001008 if (unencrypted_extension) {
1009 if (found_extension) {
1010 *found_extension = *unencrypted_extension;
1011 }
1012 return true;
1013 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014 return false;
1015}
1016
zhihuang1c378ed2017-08-17 14:10:50 -07001017// Adds all extensions from |reference_extensions| to |offered_extensions| that
1018// don't already exist in |offered_extensions| and ensure the IDs don't
1019// collide. If an extension is added, it's also added to |regular_extensions| or
1020// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1021// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1022// |offered_extensions| is for either audio or video while |regular_extensions|
1023// and |encrypted_extensions| are used for both audio and video. There could be
1024// overlap between audio extensions and video extensions.
1025static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1026 RtpHeaderExtensions* offered_extensions,
1027 RtpHeaderExtensions* regular_extensions,
1028 RtpHeaderExtensions* encrypted_extensions,
1029 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001030 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001031 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1032 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001033 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001034 if (reference_extension.encrypt) {
1035 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1036 &existing)) {
1037 offered_extensions->push_back(existing);
1038 } else {
1039 used_ids->FindAndSetIdUsed(&reference_extension);
1040 encrypted_extensions->push_back(reference_extension);
1041 offered_extensions->push_back(reference_extension);
1042 }
olka3c747662017-08-17 06:50:32 -07001043 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001044 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1045 &existing)) {
1046 offered_extensions->push_back(existing);
1047 } else {
1048 used_ids->FindAndSetIdUsed(&reference_extension);
1049 regular_extensions->push_back(reference_extension);
1050 offered_extensions->push_back(reference_extension);
1051 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001052 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 }
1054 }
1055}
1056
jbauch5869f502017-06-29 12:31:36 -07001057static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1058 RtpHeaderExtensions* all_extensions,
1059 UsedRtpHeaderExtensionIds* used_ids) {
1060 RtpHeaderExtensions encrypted_extensions;
1061 for (const webrtc::RtpExtension& extension : *extensions) {
1062 webrtc::RtpExtension existing;
1063 // Don't add encrypted extensions again that were already included in a
1064 // previous offer or regular extensions that are also included as encrypted
1065 // extensions.
1066 if (extension.encrypt ||
1067 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1068 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001069 &existing) &&
1070 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001071 continue;
1072 }
1073
1074 if (FindByUri(*all_extensions, extension, &existing)) {
1075 encrypted_extensions.push_back(existing);
1076 } else {
1077 webrtc::RtpExtension encrypted(extension);
1078 encrypted.encrypt = true;
1079 used_ids->FindAndSetIdUsed(&encrypted);
1080 all_extensions->push_back(encrypted);
1081 encrypted_extensions.push_back(encrypted);
1082 }
1083 }
1084 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001085 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001086}
1087
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088static void NegotiateRtpHeaderExtensions(
1089 const RtpHeaderExtensions& local_extensions,
1090 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001091 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001093 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001094 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001095 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001096 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001097 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 // We respond with their RTP header extension id.
1099 negotiated_extenstions->push_back(theirs);
1100 }
1101 }
1102}
1103
1104static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001105 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1106 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001107 return absl::EqualsIgnoreCase(
1108 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001109 }),
1110 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111}
1112
zhihuang1c378ed2017-08-17 14:10:50 -07001113// Create a media content to be answered for the given |sender_options|
1114// according to the given session_options.rtcp_mux, session_options.streams,
1115// codecs, crypto, and current_streams. If we don't currently have crypto (in
1116// current_cryptos) and it is enabled (in secure_policy), crypto is created
1117// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1118// negotiated with the offer. If the negotiation fails, this method returns
1119// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001120template <class C>
1121static bool CreateMediaContentAnswer(
1122 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001123 const MediaDescriptionOptions& media_description_options,
1124 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001125 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001126 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 const CryptoParamsVec* current_cryptos,
1128 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001129 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001130 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 bool bundle_enabled,
1133 MediaContentDescriptionImpl<C>* answer) {
1134 std::vector<C> negotiated_codecs;
1135 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1136 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001138
Johannes Kron9581bc42018-10-23 10:17:39 +02001139 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001141 NegotiateRtpHeaderExtensions(
1142 local_rtp_extenstions, offer->rtp_header_extensions(),
1143 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1145
zhihuang1c378ed2017-08-17 14:10:50 -07001146 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001147 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1148 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1149 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150
1151 if (sdes_policy != SEC_DISABLED) {
1152 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001153 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1154 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 if (current_cryptos) {
1156 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1157 }
1158 answer->AddCrypto(crypto);
1159 }
1160 }
1161
deadbeef7af91dd2016-12-13 11:29:11 -08001162 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163 return false;
1164 }
1165
zhihuang1c378ed2017-08-17 14:10:50 -07001166 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001167 session_options.rtcp_cname, ssrc_generator,
1168 current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 return false; // Something went seriously wrong.
1170 }
1171
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001172 AddSimulcastToMediaDescription(media_description_options, answer);
1173
Steve Anton4e70a722017-11-28 14:57:10 -08001174 answer->set_direction(NegotiateRtpTransceiverDirection(
1175 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176 return true;
1177}
1178
1179static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001180 const std::string& protocol,
1181 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001182 // Since not all applications serialize and deserialize the media protocol,
1183 // we will have to accept |protocol| to be empty.
1184 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185 return true;
1186 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001187
zhihuangcf5b37c2016-05-05 11:44:35 -07001188 if (type == MEDIA_TYPE_DATA) {
1189 // Check for SCTP, but also for RTP for RTP-based data channels.
1190 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1191 if (secure_transport) {
1192 // Most likely scenarios first.
1193 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1194 IsPlainRtp(protocol);
1195 } else {
1196 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1197 }
1198 }
1199
1200 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1201 // JSEP specifies.
1202 if (secure_transport) {
1203 // Most likely scenarios first.
1204 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1205 } else {
1206 return IsPlainRtp(protocol);
1207 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208}
1209
1210static void SetMediaProtocol(bool secure_transport,
1211 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001212 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001214 else if (secure_transport)
1215 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001216 else
1217 desc->set_protocol(kMediaProtocolAvpf);
1218}
1219
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001220// Gets the TransportInfo of the given |content_name| from the
1221// |current_description|. If doesn't exist, returns a new one.
1222static const TransportDescription* GetTransportDescription(
1223 const std::string& content_name,
1224 const SessionDescription* current_description) {
1225 const TransportDescription* desc = NULL;
1226 if (current_description) {
1227 const TransportInfo* info =
1228 current_description->GetTransportInfoByName(content_name);
1229 if (info) {
1230 desc = &info->description;
1231 }
1232 }
1233 return desc;
1234}
1235
1236// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001237static bool IsDtlsActive(const ContentInfo* content,
1238 const SessionDescription* current_description) {
1239 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001240 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001241 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001242
zhihuang1c378ed2017-08-17 14:10:50 -07001243 size_t msection_index = content - &current_description->contents()[0];
1244
1245 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001246 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001247 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001248
zhihuang1c378ed2017-08-17 14:10:50 -07001249 return current_description->transport_infos()[msection_index]
1250 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001251}
1252
Steve Anton8ffb9c32017-08-31 15:45:38 -07001253void MediaDescriptionOptions::AddAudioSender(
1254 const std::string& track_id,
1255 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001256 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001257 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001258}
1259
Steve Anton8ffb9c32017-08-31 15:45:38 -07001260void MediaDescriptionOptions::AddVideoSender(
1261 const std::string& track_id,
1262 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001263 const std::vector<RidDescription>& rids,
1264 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001265 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001266 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001267 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1268 << "RIDs are the compliant way to indicate simulcast.";
1269 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1270 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1271 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001272}
1273
zhihuang1c378ed2017-08-17 14:10:50 -07001274void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1275 const std::string& stream_id) {
1276 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001277 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1278 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001279 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280}
1281
Steve Anton8ffb9c32017-08-31 15:45:38 -07001282void MediaDescriptionOptions::AddSenderInternal(
1283 const std::string& track_id,
1284 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001285 const std::vector<RidDescription>& rids,
1286 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001287 int num_sim_layers) {
1288 // TODO(steveanton): Support any number of stream ids.
1289 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001290 SenderOptions options;
1291 options.track_id = track_id;
1292 options.stream_ids = stream_ids;
1293 options.simulcast_layers = simulcast_layers;
1294 options.rids = rids;
1295 options.num_sim_layers = num_sim_layers;
1296 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297}
1298
zhihuang1c378ed2017-08-17 14:10:50 -07001299bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001300 return absl::c_any_of(
1301 media_description_options,
1302 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001303}
1304
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001306 const TransportDescriptionFactory* transport_desc_factory,
1307 rtc::UniqueRandomIdGenerator* ssrc_generator)
1308 : ssrc_generator_(ssrc_generator),
1309 transport_desc_factory_(transport_desc_factory) {
1310 RTC_DCHECK(ssrc_generator_);
1311}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312
1313MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1314 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001315 const TransportDescriptionFactory* transport_desc_factory,
1316 rtc::UniqueRandomIdGenerator* ssrc_generator)
1317 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001318 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1319 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001321 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1323 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001324 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001325}
1326
ossudedfd282016-06-14 07:12:39 -07001327const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1328 const {
ossu075af922016-06-14 03:29:38 -07001329 return audio_sendrecv_codecs_;
1330}
1331
1332const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1333 return audio_send_codecs_;
1334}
1335
1336const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1337 return audio_recv_codecs_;
1338}
1339
1340void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001341 const AudioCodecs& send_codecs,
1342 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001343 audio_send_codecs_ = send_codecs;
1344 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001345 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001346}
1347
Amit Hilbuch77938e62018-12-21 09:23:38 -08001348static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1349 RTC_DCHECK(extensions);
1350 // Unified Plan also offers the MID and RID header extensions.
1351 extensions->push_back(webrtc::RtpExtension(
1352 webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
1353 extensions->push_back(webrtc::RtpExtension(
1354 webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRidDefaultId));
1355 extensions->push_back(
1356 webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri,
1357 webrtc::RtpExtension::kRepairedRidDefaultId));
1358}
1359
1360RtpHeaderExtensions
1361MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1362 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1363 if (is_unified_plan_) {
1364 AddUnifiedPlanExtensions(&extensions);
1365 }
1366
1367 return extensions;
1368}
1369
1370RtpHeaderExtensions
1371MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1372 RtpHeaderExtensions extensions = video_rtp_extensions_;
1373 if (is_unified_plan_) {
1374 AddUnifiedPlanExtensions(&extensions);
1375 }
1376
1377 return extensions;
1378}
1379
Steve Anton6fe1fba2018-12-11 10:15:23 -08001380std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001381 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001383 // Must have options for each existing section.
1384 if (current_description) {
1385 RTC_DCHECK_LE(current_description->contents().size(),
1386 session_options.media_description_options.size());
1387 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001388
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001389 IceCredentialsIterator ice_credentials(
1390 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001391
1392 std::vector<const ContentInfo*> current_active_contents;
1393 if (current_description) {
1394 current_active_contents =
1395 GetActiveContents(*current_description, session_options);
1396 }
1397
1398 StreamParamsVec current_streams =
1399 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001400
zhihuang1c378ed2017-08-17 14:10:50 -07001401 AudioCodecs offer_audio_codecs;
1402 VideoCodecs offer_video_codecs;
1403 DataCodecs offer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001404 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001405 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001406
zhihuang1c378ed2017-08-17 14:10:50 -07001407 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001408 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001409 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001410 }
zhihuang1c378ed2017-08-17 14:10:50 -07001411 FilterDataCodecs(&offer_data_codecs,
1412 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001413
1414 RtpHeaderExtensions audio_rtp_extensions;
1415 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001416 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1417 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001418
Steve Anton5c72e712018-12-10 14:25:30 -08001419 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001420
zhihuang1c378ed2017-08-17 14:10:50 -07001421 // Iterate through the media description options, matching with existing media
1422 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001423 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001424 for (const MediaDescriptionOptions& media_description_options :
1425 session_options.media_description_options) {
1426 const ContentInfo* current_content = nullptr;
1427 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001428 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001429 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001430 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001431 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001432 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001433 media_description_options.type));
1434 }
1435 switch (media_description_options.type) {
1436 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001437 if (!AddAudioContentForOffer(
1438 media_description_options, session_options, current_content,
1439 current_description, audio_rtp_extensions, offer_audio_codecs,
1440 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001441 return nullptr;
1442 }
1443 break;
1444 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001445 if (!AddVideoContentForOffer(
1446 media_description_options, session_options, current_content,
1447 current_description, video_rtp_extensions, offer_video_codecs,
1448 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001449 return nullptr;
1450 }
1451 break;
1452 case MEDIA_TYPE_DATA:
1453 if (!AddDataContentForOffer(media_description_options, session_options,
1454 current_content, current_description,
1455 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001456 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001457 return nullptr;
1458 }
1459 break;
1460 default:
1461 RTC_NOTREACHED();
1462 }
1463 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001464 }
1465
1466 // Bundle the contents together, if we've been asked to do so, and update any
1467 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001468 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001470 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001471 if (content.rejected) {
1472 continue;
1473 }
zhihuang1c378ed2017-08-17 14:10:50 -07001474 // TODO(deadbeef): There are conditions that make bundling two media
1475 // descriptions together illegal. For example, they use the same payload
1476 // type to represent different codecs, or same IDs for different header
1477 // extensions. We need to detect this and not try to bundle those media
1478 // descriptions together.
1479 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001480 }
Steve Anton2bed3972019-01-04 17:04:30 -08001481 if (!offer_bundle.content_names().empty()) {
1482 offer->AddGroup(offer_bundle);
1483 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1484 RTC_LOG(LS_ERROR)
1485 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1486 return nullptr;
1487 }
1488 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1489 RTC_LOG(LS_ERROR)
1490 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1491 return nullptr;
1492 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001493 }
1494 }
Steve Antone831b8c2018-02-01 12:22:16 -08001495
1496 // The following determines how to signal MSIDs to ensure compatibility with
1497 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001498 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001499 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1500 // Plan answerers will look at a=msid and Plan B answerers will look at the
1501 // a=ssrc MSID line.
1502 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1503 cricket::kMsidSignalingSsrcAttribute);
1504 } else {
1505 // Plan B always signals MSID using a=ssrc lines.
1506 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1507 }
1508
Johannes Kron89f874e2018-11-12 10:25:48 +01001509 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1510
Steve Anton6fe1fba2018-12-11 10:15:23 -08001511 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512}
1513
Steve Anton6fe1fba2018-12-11 10:15:23 -08001514std::unique_ptr<SessionDescription>
1515MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001516 const SessionDescription* offer,
1517 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001519 if (!offer) {
1520 return nullptr;
1521 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001522
Steve Anton5c72e712018-12-10 14:25:30 -08001523 // Must have options for exactly as many sections as in the offer.
1524 RTC_DCHECK_EQ(offer->contents().size(),
1525 session_options.media_description_options.size());
1526
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001527 IceCredentialsIterator ice_credentials(
1528 session_options.pooled_ice_credentials);
1529
Steve Anton5c72e712018-12-10 14:25:30 -08001530 std::vector<const ContentInfo*> current_active_contents;
1531 if (current_description) {
1532 current_active_contents =
1533 GetActiveContents(*current_description, session_options);
1534 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535
Steve Anton5c72e712018-12-10 14:25:30 -08001536 StreamParamsVec current_streams =
1537 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001538
zhihuang1c378ed2017-08-17 14:10:50 -07001539 // Get list of all possible codecs that respects existing payload type
1540 // mappings and uses a single payload type space.
1541 //
1542 // Note that these lists may be further filtered for each m= section; this
1543 // step is done just to establish the payload type mappings shared by all
1544 // sections.
1545 AudioCodecs answer_audio_codecs;
1546 VideoCodecs answer_video_codecs;
1547 DataCodecs answer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001548 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001549 &answer_video_codecs, &answer_data_codecs);
1550
1551 if (!session_options.vad_enabled) {
1552 // If application doesn't want CN codecs in answer.
1553 StripCNCodecs(&answer_audio_codecs);
1554 }
1555 FilterDataCodecs(&answer_data_codecs,
1556 session_options.data_channel_type == DCT_SCTP);
1557
Steve Anton5c72e712018-12-10 14:25:30 -08001558 auto answer = absl::make_unique<SessionDescription>();
1559
1560 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1561 // group in the answer with the appropriate content names.
1562 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1563 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1564 // Transport info shared by the bundle group.
1565 std::unique_ptr<TransportInfo> bundle_transport;
1566
1567 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1568
zhihuang1c378ed2017-08-17 14:10:50 -07001569 // Iterate through the media description options, matching with existing
1570 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001571 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001572 for (const MediaDescriptionOptions& media_description_options :
1573 session_options.media_description_options) {
1574 const ContentInfo* offer_content = &offer->contents()[msection_index];
1575 // Media types and MIDs must match between the remote offer and the
1576 // MediaDescriptionOptions.
1577 RTC_DCHECK(
1578 IsMediaContentOfType(offer_content, media_description_options.type));
1579 RTC_DCHECK(media_description_options.mid == offer_content->name);
1580 const ContentInfo* current_content = nullptr;
1581 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001582 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001583 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001584 }
zhihuang1c378ed2017-08-17 14:10:50 -07001585 switch (media_description_options.type) {
1586 case MEDIA_TYPE_AUDIO:
1587 if (!AddAudioContentForAnswer(
1588 media_description_options, session_options, offer_content,
1589 offer, current_content, current_description,
1590 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001591 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001592 return nullptr;
1593 }
1594 break;
1595 case MEDIA_TYPE_VIDEO:
1596 if (!AddVideoContentForAnswer(
1597 media_description_options, session_options, offer_content,
1598 offer, current_content, current_description,
1599 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001600 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001601 return nullptr;
1602 }
1603 break;
1604 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001605 if (!AddDataContentForAnswer(
1606 media_description_options, session_options, offer_content,
1607 offer, current_content, current_description,
1608 bundle_transport.get(), answer_data_codecs, &current_streams,
1609 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001610 return nullptr;
1611 }
1612 break;
1613 default:
1614 RTC_NOTREACHED();
1615 }
1616 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001617 // See if we can add the newly generated m= section to the BUNDLE group in
1618 // the answer.
1619 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001620 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001621 offer_bundle->HasContentName(added.name)) {
1622 answer_bundle.AddContentName(added.name);
1623 bundle_transport.reset(
1624 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 }
1627
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001628 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1629 // it's empty. RFC5888 says:
1630 //
1631 // A SIP entity that receives an offer that contains an "a=group" line
1632 // with semantics that are understood MUST return an answer that
1633 // contains an "a=group" line with the same semantics.
1634 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001635 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001636 }
deadbeefb7892532017-02-22 19:35:18 -08001637
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001638 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001639 // Share the same ICE credentials and crypto params across all contents,
1640 // as BUNDLE requires.
1641 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001642 RTC_LOG(LS_ERROR)
1643 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001644 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646
deadbeefb7892532017-02-22 19:35:18 -08001647 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001648 RTC_LOG(LS_ERROR)
1649 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001650 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001651 }
1652 }
1653
Steve Antone831b8c2018-02-01 12:22:16 -08001654 // The following determines how to signal MSIDs to ensure compatibility with
1655 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001656 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001657 // Unified Plan needs to look at what the offer included to find the most
1658 // compatible answer.
1659 if (offer->msid_signaling() == 0) {
1660 // We end up here in one of three cases:
1661 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1662 // matter what we pick here.
1663 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1664 // it also doesn't matter what we pick here.
1665 // 3. Media that's either sendonly or inactive from the remote endpoint.
1666 // We don't have any information to say whether the endpoint is Plan B
1667 // or Unified Plan, so be conservative and send both.
1668 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1669 cricket::kMsidSignalingSsrcAttribute);
1670 } else if (offer->msid_signaling() ==
1671 (cricket::kMsidSignalingMediaSection |
1672 cricket::kMsidSignalingSsrcAttribute)) {
1673 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1674 // probably talking to a Unified Plan endpoint so respond with just
1675 // a=msid.
1676 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1677 } else {
1678 // Otherwise, it's clear which method the offerer is using so repeat that
1679 // back to them.
1680 answer->set_msid_signaling(offer->msid_signaling());
1681 }
1682 } else {
1683 // Plan B always signals MSID using a=ssrc lines.
1684 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1685 }
1686
Steve Anton6fe1fba2018-12-11 10:15:23 -08001687 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688}
1689
ossu075af922016-06-14 03:29:38 -07001690const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1691 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001692 switch (direction) {
1693 // If stream is inactive - generate list as if sendrecv.
1694 case RtpTransceiverDirection::kSendRecv:
1695 case RtpTransceiverDirection::kInactive:
1696 return audio_sendrecv_codecs_;
1697 case RtpTransceiverDirection::kSendOnly:
1698 return audio_send_codecs_;
1699 case RtpTransceiverDirection::kRecvOnly:
1700 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001701 }
Steve Anton1d03a752017-11-27 14:30:09 -08001702 RTC_NOTREACHED();
1703 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001704}
1705
1706const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1707 const RtpTransceiverDirection& offer,
1708 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001709 switch (answer) {
1710 // For inactive and sendrecv answers, generate lists as if we were to accept
1711 // the offer's direction. See RFC 3264 Section 6.1.
1712 case RtpTransceiverDirection::kSendRecv:
1713 case RtpTransceiverDirection::kInactive:
1714 return GetAudioCodecsForOffer(
1715 webrtc::RtpTransceiverDirectionReversed(offer));
1716 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001717 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001718 case RtpTransceiverDirection::kRecvOnly:
1719 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001720 }
Steve Anton1d03a752017-11-27 14:30:09 -08001721 RTC_NOTREACHED();
1722 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001723}
1724
Steve Anton5c72e712018-12-10 14:25:30 -08001725void MergeCodecsFromDescription(
1726 const std::vector<const ContentInfo*>& current_active_contents,
1727 AudioCodecs* audio_codecs,
1728 VideoCodecs* video_codecs,
1729 DataCodecs* data_codecs,
1730 UsedPayloadTypes* used_pltypes) {
1731 for (const ContentInfo* content : current_active_contents) {
1732 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001733 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001734 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001735 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001736 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001737 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001738 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001739 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001740 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001741 const DataContentDescription* data =
Steve Anton5c72e712018-12-10 14:25:30 -08001742 content->media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001743 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1744 }
1745 }
1746}
1747
1748// Getting codecs for an offer involves these steps:
1749//
1750// 1. Construct payload type -> codec mappings for current description.
1751// 2. Add any reference codecs that weren't already present
1752// 3. For each individual media description (m= section), filter codecs based
1753// on the directional attribute (happens in another method).
1754void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001755 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756 AudioCodecs* audio_codecs,
1757 VideoCodecs* video_codecs,
1758 DataCodecs* data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001759 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001760 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1761 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001762 UsedPayloadTypes used_pltypes;
1763 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1764 video_codecs, data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001765
Steve Anton5c72e712018-12-10 14:25:30 -08001766 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001767 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1768 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1769 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1770}
1771
1772// Getting codecs for an answer involves these steps:
1773//
1774// 1. Construct payload type -> codec mappings for current description.
1775// 2. Add any codecs from the offer that weren't already present.
1776// 3. Add any remaining codecs that weren't already present.
1777// 4. For each individual media description (m= section), filter codecs based
1778// on the directional attribute (happens in another method).
1779void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001780 const std::vector<const ContentInfo*>& current_active_contents,
1781 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001782 AudioCodecs* audio_codecs,
1783 VideoCodecs* video_codecs,
1784 DataCodecs* data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001785 // First - get all codecs from the current description if the media type
1786 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1787 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001788 UsedPayloadTypes used_pltypes;
1789 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1790 video_codecs, data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001791
1792 // Second - filter out codecs that we don't support at all and should ignore.
1793 AudioCodecs filtered_offered_audio_codecs;
1794 VideoCodecs filtered_offered_video_codecs;
1795 DataCodecs filtered_offered_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001796 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001797 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1798 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001799 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001800 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1801 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1802 filtered_offered_audio_codecs,
1803 offered_audio_codec, nullptr) &&
1804 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1805 offered_audio_codec, nullptr)) {
1806 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1807 }
1808 }
1809 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1810 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001811 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001812 for (const VideoCodec& offered_video_codec : video->codecs()) {
1813 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1814 filtered_offered_video_codecs,
1815 offered_video_codec, nullptr) &&
1816 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1817 offered_video_codec, nullptr)) {
1818 filtered_offered_video_codecs.push_back(offered_video_codec);
1819 }
1820 }
1821 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1822 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001823 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001824 for (const DataCodec& offered_data_codec : data->codecs()) {
1825 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1826 filtered_offered_data_codecs,
1827 offered_data_codec, nullptr) &&
1828 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1829 offered_data_codec, nullptr)) {
1830 filtered_offered_data_codecs.push_back(offered_data_codec);
1831 }
1832 }
1833 }
1834 }
1835
Steve Anton5c72e712018-12-10 14:25:30 -08001836 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001837 // |remote_offer|.
1838 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1839 &used_pltypes);
1840 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1841 &used_pltypes);
1842 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1843 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844}
1845
1846void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001847 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001848 RtpHeaderExtensions* offer_audio_extensions,
1849 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001850 // All header extensions allocated from the same range to avoid potential
1851 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001852 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001853 RtpHeaderExtensions all_regular_extensions;
1854 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001855
1856 // First - get all extensions from the current description if the media type
1857 // is used.
1858 // Add them to |used_ids| so the local ids are not reused if a new media
1859 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001860 for (const ContentInfo* content : current_active_contents) {
1861 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1862 const AudioContentDescription* audio =
1863 content->media_description()->as_audio();
1864 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1865 &all_regular_extensions, &all_encrypted_extensions,
1866 &used_ids);
1867 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1868 const VideoContentDescription* video =
1869 content->media_description()->as_video();
1870 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1871 &all_regular_extensions, &all_encrypted_extensions,
1872 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873 }
1874 }
1875
Steve Anton5c72e712018-12-10 14:25:30 -08001876 // Add our default RTP header extensions that are not in the current
1877 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001878 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1879 &all_regular_extensions, &all_encrypted_extensions,
1880 &used_ids);
1881 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1882 &all_regular_extensions, &all_encrypted_extensions,
1883 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001884
jbauch5869f502017-06-29 12:31:36 -07001885 // TODO(jbauch): Support adding encrypted header extensions to existing
1886 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001887 if (enable_encrypted_rtp_header_extensions_ &&
1888 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001889 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1890 &all_encrypted_extensions, &used_ids);
1891 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1892 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001893 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001894}
1895
1896bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001897 const std::string& content_name,
1898 const TransportOptions& transport_options,
1899 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001900 SessionDescription* offer_desc,
1901 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001903 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 const TransportDescription* current_tdesc =
1905 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001906 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001907 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1908 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001909 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001910 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1911 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 }
Steve Anton06817cd2018-12-18 15:55:30 -08001913 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1914 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915}
1916
Steve Anton1a9d3c32018-12-10 17:18:54 -08001917std::unique_ptr<TransportDescription>
1918MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 const std::string& content_name,
1920 const SessionDescription* offer_desc,
1921 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001922 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001923 bool require_transport_attributes,
1924 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925 if (!transport_desc_factory_)
1926 return NULL;
1927 const TransportDescription* offer_tdesc =
1928 GetTransportDescription(content_name, offer_desc);
1929 const TransportDescription* current_tdesc =
1930 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001931 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1932 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001933 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001934}
1935
1936bool MediaSessionDescriptionFactory::AddTransportAnswer(
1937 const std::string& content_name,
1938 const TransportDescription& transport_desc,
1939 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001940 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 return true;
1942}
1943
zhihuang1c378ed2017-08-17 14:10:50 -07001944// |audio_codecs| = set of all possible codecs that can be used, with correct
1945// payload type mappings
1946//
1947// |supported_audio_codecs| = set of codecs that are supported for the direction
1948// of this m= section
1949//
1950// acd->codecs() = set of previously negotiated codecs for this m= section
1951//
1952// The payload types should come from audio_codecs, but the order should come
1953// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1954// change existing codec priority, and that new codecs are added with the right
1955// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001956bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001957 const MediaDescriptionOptions& media_description_options,
1958 const MediaSessionOptions& session_options,
1959 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001960 const SessionDescription* current_description,
1961 const RtpHeaderExtensions& audio_rtp_extensions,
1962 const AudioCodecs& audio_codecs,
1963 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001964 SessionDescription* desc,
1965 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001966 // Filter audio_codecs (which includes all codecs, with correctly remapped
1967 // payload types) based on transceiver direction.
1968 const AudioCodecs& supported_audio_codecs =
1969 GetAudioCodecsForOffer(media_description_options.direction);
1970
1971 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001972 // Add the codecs from current content if it exists and is not rejected nor
1973 // recycled.
1974 if (current_content && !current_content->rejected &&
1975 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001976 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001977 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001978 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001979 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001980 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1981 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001982 filtered_codecs.push_back(codec);
1983 }
1984 }
1985 }
1986 // Add other supported audio codecs.
1987 AudioCodec found_codec;
1988 for (const AudioCodec& codec : supported_audio_codecs) {
1989 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1990 codec, &found_codec) &&
1991 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1992 codec, nullptr)) {
1993 // Use the |found_codec| from |audio_codecs| because it has the correctly
1994 // mapped payload type.
1995 filtered_codecs.push_back(found_codec);
1996 }
1997 }
deadbeef44f08192015-12-15 16:20:09 -08001998
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001999 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002000 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2001 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002002
kwiberg31022942016-03-11 14:18:21 -08002003 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002004 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002005 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2006 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002007 if (!CreateMediaContentOffer(media_description_options, session_options,
2008 filtered_codecs, sdes_policy,
2009 GetCryptos(current_content), crypto_suites,
2010 audio_rtp_extensions, ssrc_generator_,
2011 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002012 return false;
2013 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002014
2015 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2016 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002017
Steve Anton4e70a722017-11-28 14:57:10 -08002018 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002019
Steve Anton5adfafd2017-12-20 16:34:00 -08002020 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002021 media_description_options.stopped, audio.release());
2022 if (!AddTransportOffer(media_description_options.mid,
2023 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002024 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002025 return false;
2026 }
2027
2028 return true;
2029}
2030
2031bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002032 const MediaDescriptionOptions& media_description_options,
2033 const MediaSessionOptions& session_options,
2034 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002035 const SessionDescription* current_description,
2036 const RtpHeaderExtensions& video_rtp_extensions,
2037 const VideoCodecs& video_codecs,
2038 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002039 SessionDescription* desc,
2040 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002041 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002042 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2043 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002044
kwiberg31022942016-03-11 14:18:21 -08002045 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002046 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002047 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2048 &crypto_suites);
2049
2050 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002051 // Add the codecs from current content if it exists and is not rejected nor
2052 // recycled.
2053 if (current_content && !current_content->rejected &&
2054 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002055 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002056 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002057 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002058 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002059 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002060 nullptr)) {
2061 filtered_codecs.push_back(codec);
2062 }
2063 }
2064 }
2065 // Add other supported video codecs.
2066 VideoCodec found_codec;
2067 for (const VideoCodec& codec : video_codecs_) {
2068 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2069 &found_codec) &&
2070 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2071 nullptr)) {
2072 // Use the |found_codec| from |video_codecs| because it has the correctly
2073 // mapped payload type.
2074 filtered_codecs.push_back(found_codec);
2075 }
2076 }
2077
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002078 if (!CreateMediaContentOffer(media_description_options, session_options,
2079 filtered_codecs, sdes_policy,
2080 GetCryptos(current_content), crypto_suites,
2081 video_rtp_extensions, ssrc_generator_,
2082 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002083 return false;
2084 }
2085
zhihuang1c378ed2017-08-17 14:10:50 -07002086 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002087
2088 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2089 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002090
Steve Anton4e70a722017-11-28 14:57:10 -08002091 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002092
Steve Anton5adfafd2017-12-20 16:34:00 -08002093 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002094 media_description_options.stopped, video.release());
2095 if (!AddTransportOffer(media_description_options.mid,
2096 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002097 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002098 return false;
2099 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002100 return true;
2101}
2102
2103bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002104 const MediaDescriptionOptions& media_description_options,
2105 const MediaSessionOptions& session_options,
2106 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002107 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07002108 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002109 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002110 SessionDescription* desc,
2111 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002112 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2113
kwiberg31022942016-03-11 14:18:21 -08002114 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07002115 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2116 // If the DataChannel type is not specified, use the DataChannel type in
2117 // the current description.
2118 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002119 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002120 is_sctp = (current_content->media_description()->protocol() ==
2121 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002122 }
deadbeef44f08192015-12-15 16:20:09 -08002123
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002124 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002125 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2126 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002127 std::vector<std::string> crypto_suites;
2128 if (is_sctp) {
2129 // SDES doesn't make sense for SCTP, so we disable it, and we only
2130 // get SDES crypto suites for RTP-based data channels.
2131 sdes_policy = cricket::SEC_DISABLED;
2132 // Unlike SetMediaProtocol below, we need to set the protocol
2133 // before we call CreateMediaContentOffer. Otherwise,
2134 // CreateMediaContentOffer won't know this is SCTP and will
2135 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002136 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2137 // it's safe to do so. Older versions of webrtc would reject these
2138 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002139 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2140 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002141 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002142 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002143 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002144 }
2145
zhihuang1c378ed2017-08-17 14:10:50 -07002146 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002147 if (!CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002148 media_description_options, session_options, data_codecs, sdes_policy,
2149 GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002150 ssrc_generator_, current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002151 return false;
2152 }
2153
2154 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002155 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002156 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002157 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002158 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002159 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002160 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002161 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002162 }
zhihuang1c378ed2017-08-17 14:10:50 -07002163 if (!AddTransportOffer(media_description_options.mid,
2164 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002165 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002166 return false;
2167 }
2168 return true;
2169}
2170
zhihuang1c378ed2017-08-17 14:10:50 -07002171// |audio_codecs| = set of all possible codecs that can be used, with correct
2172// payload type mappings
2173//
2174// |supported_audio_codecs| = set of codecs that are supported for the direction
2175// of this m= section
2176//
2177// acd->codecs() = set of previously negotiated codecs for this m= section
2178//
2179// The payload types should come from audio_codecs, but the order should come
2180// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2181// change existing codec priority, and that new codecs are added with the right
2182// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002183bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002184 const MediaDescriptionOptions& media_description_options,
2185 const MediaSessionOptions& session_options,
2186 const ContentInfo* offer_content,
2187 const SessionDescription* offer_description,
2188 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002189 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002190 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002191 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002192 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002193 SessionDescription* answer,
2194 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002195 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002196 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002197 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002198
Steve Anton1a9d3c32018-12-10 17:18:54 -08002199 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002200 media_description_options.mid, offer_description,
2201 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002202 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002203 if (!audio_transport) {
2204 return false;
2205 }
2206
zhihuang1c378ed2017-08-17 14:10:50 -07002207 // Pick codecs based on the requested communications direction in the offer
2208 // and the selected direction in the answer.
2209 // Note these will be filtered one final time in CreateMediaContentAnswer.
2210 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002211 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002212 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002213 AudioCodecs supported_audio_codecs =
2214 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2215
2216 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002217 // Add the codecs from current content if it exists and is not rejected nor
2218 // recycled.
2219 if (current_content && !current_content->rejected &&
2220 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002221 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002222 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002223 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002224 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002225 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2226 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002227 filtered_codecs.push_back(codec);
2228 }
2229 }
2230 }
2231 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002232 for (const AudioCodec& codec : supported_audio_codecs) {
2233 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002234 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002235 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2236 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002237 // We should use the local codec with local parameters and the codec id
2238 // would be correctly mapped in |NegotiateCodecs|.
2239 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002240 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002241 }
2242
zhihuang1c378ed2017-08-17 14:10:50 -07002243 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2244 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002245 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002246 new AudioContentDescription());
2247 // Do not require or create SDES cryptos if DTLS is used.
2248 cricket::SecurePolicy sdes_policy =
2249 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2250 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002251 offer_audio_description, media_description_options, session_options,
2252 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002253 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002254 enable_encrypted_rtp_header_extensions_, current_streams,
2255 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002256 return false; // Fails the session setup.
2257 }
2258
deadbeefb7892532017-02-22 19:35:18 -08002259 bool secure = bundle_transport ? bundle_transport->description.secure()
2260 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002261 bool rejected = media_description_options.stopped ||
2262 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002263 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2264 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002265 if (!AddTransportAnswer(media_description_options.mid,
2266 *(audio_transport.get()), answer)) {
2267 return false;
2268 }
2269
2270 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002271 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2272 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 }
2274
zhihuang1c378ed2017-08-17 14:10:50 -07002275 answer->AddContent(media_description_options.mid, offer_content->type,
2276 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002277 return true;
2278}
2279
2280bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002281 const MediaDescriptionOptions& media_description_options,
2282 const MediaSessionOptions& session_options,
2283 const ContentInfo* offer_content,
2284 const SessionDescription* offer_description,
2285 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002286 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002287 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002288 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002289 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002290 SessionDescription* answer,
2291 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002292 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002293 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002294 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002295
Steve Anton1a9d3c32018-12-10 17:18:54 -08002296 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002297 media_description_options.mid, offer_description,
2298 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002299 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002300 if (!video_transport) {
2301 return false;
2302 }
2303
zhihuang1c378ed2017-08-17 14:10:50 -07002304 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002305 // Add the codecs from current content if it exists and is not rejected nor
2306 // recycled.
2307 if (current_content && !current_content->rejected &&
2308 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002309 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002310 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002311 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002312 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002313 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002314 nullptr)) {
2315 filtered_codecs.push_back(codec);
2316 }
2317 }
2318 }
2319 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002320 for (const VideoCodec& codec : video_codecs_) {
2321 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002322 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002323 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2324 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002325 // We should use the local codec with local parameters and the codec id
2326 // would be correctly mapped in |NegotiateCodecs|.
2327 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002328 }
2329 }
2330
2331 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2332 session_options.bundle_enabled;
2333
kwiberg31022942016-03-11 14:18:21 -08002334 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002335 new VideoContentDescription());
2336 // Do not require or create SDES cryptos if DTLS is used.
2337 cricket::SecurePolicy sdes_policy =
2338 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002339 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002340 offer_video_description, media_description_options, session_options,
2341 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002342 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002343 enable_encrypted_rtp_header_extensions_, current_streams,
2344 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002345 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002346 }
deadbeefb7892532017-02-22 19:35:18 -08002347 bool secure = bundle_transport ? bundle_transport->description.secure()
2348 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002349 bool rejected = media_description_options.stopped ||
2350 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002351 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2352 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002353 if (!AddTransportAnswer(media_description_options.mid,
2354 *(video_transport.get()), answer)) {
2355 return false;
2356 }
2357
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002358 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002359 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002360 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002361 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2362 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002363 }
zhihuang1c378ed2017-08-17 14:10:50 -07002364 answer->AddContent(media_description_options.mid, offer_content->type,
2365 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002366 return true;
2367}
2368
2369bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002370 const MediaDescriptionOptions& media_description_options,
2371 const MediaSessionOptions& session_options,
2372 const ContentInfo* offer_content,
2373 const SessionDescription* offer_description,
2374 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002375 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002376 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002377 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002378 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002379 SessionDescription* answer,
2380 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002381 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002382 media_description_options.mid, offer_description,
2383 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002384 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002385 if (!data_transport) {
2386 return false;
2387 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002388
kwiberg31022942016-03-11 14:18:21 -08002389 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002390 new DataContentDescription());
2391 // Do not require or create SDES cryptos if DTLS is used.
2392 cricket::SecurePolicy sdes_policy =
2393 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002394 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2395 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002396 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2397 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002398 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002399 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002400 offer_data_description, media_description_options, session_options,
2401 data_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002402 RtpHeaderExtensions(), ssrc_generator_,
2403 enable_encrypted_rtp_header_extensions_, current_streams,
2404 bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002405 return false; // Fails the session setup.
2406 }
2407
zstein4b2e0822017-02-17 19:48:38 -08002408 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002409 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2410 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2411
deadbeefb7892532017-02-22 19:35:18 -08002412 bool secure = bundle_transport ? bundle_transport->description.secure()
2413 : data_transport->secure();
2414
zhihuang1c378ed2017-08-17 14:10:50 -07002415 bool rejected = session_options.data_channel_type == DCT_NONE ||
2416 media_description_options.stopped ||
2417 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002418 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2419 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002420 if (!AddTransportAnswer(media_description_options.mid,
2421 *(data_transport.get()), answer)) {
2422 return false;
2423 }
2424
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002425 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002426 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002427 } else {
2428 // RFC 3264
2429 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002430 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002431 }
zhihuang1c378ed2017-08-17 14:10:50 -07002432 answer->AddContent(media_description_options.mid, offer_content->type,
2433 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002434 return true;
2435}
2436
zhihuang1c378ed2017-08-17 14:10:50 -07002437void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2438 audio_sendrecv_codecs_.clear();
2439 all_audio_codecs_.clear();
2440 // Compute the audio codecs union.
2441 for (const AudioCodec& send : audio_send_codecs_) {
2442 all_audio_codecs_.push_back(send);
2443 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2444 send, nullptr)) {
2445 // It doesn't make sense to have an RTX codec we support sending but not
2446 // receiving.
2447 RTC_DCHECK(!IsRtxCodec(send));
2448 }
2449 }
2450 for (const AudioCodec& recv : audio_recv_codecs_) {
2451 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2452 recv, nullptr)) {
2453 all_audio_codecs_.push_back(recv);
2454 }
2455 }
2456 // Use NegotiateCodecs to merge our codec lists, since the operation is
2457 // essentially the same. Put send_codecs as the offered_codecs, which is the
2458 // order we'd like to follow. The reasoning is that encoding is usually more
2459 // expensive than decoding, and prioritizing a codec in the send list probably
2460 // means it's a codec we can handle efficiently.
2461 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2462 &audio_sendrecv_codecs_);
2463}
2464
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002465bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002466 return (content && (content->type == MediaProtocolType::kRtp ||
2467 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002468}
2469
2470bool IsAudioContent(const ContentInfo* content) {
2471 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2472}
2473
2474bool IsVideoContent(const ContentInfo* content) {
2475 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2476}
2477
2478bool IsDataContent(const ContentInfo* content) {
2479 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2480}
2481
deadbeef0ed85b22016-02-23 17:24:52 -08002482const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2483 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002484 for (const ContentInfo& content : contents) {
2485 if (IsMediaContentOfType(&content, media_type)) {
2486 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002487 }
2488 }
deadbeef0ed85b22016-02-23 17:24:52 -08002489 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002490}
2491
2492const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2493 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2494}
2495
2496const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2497 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2498}
2499
2500const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2501 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2502}
2503
Steve Antonad7bffc2018-01-22 10:21:56 -08002504const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2505 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002506 if (sdesc == nullptr) {
2507 return nullptr;
2508 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002509
2510 return GetFirstMediaContent(sdesc->contents(), media_type);
2511}
2512
2513const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2514 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2515}
2516
2517const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2518 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2519}
2520
2521const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2522 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2523}
2524
2525const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002526 const SessionDescription* sdesc,
2527 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002529 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530}
2531
2532const AudioContentDescription* GetFirstAudioContentDescription(
2533 const SessionDescription* sdesc) {
2534 return static_cast<const AudioContentDescription*>(
2535 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2536}
2537
2538const VideoContentDescription* GetFirstVideoContentDescription(
2539 const SessionDescription* sdesc) {
2540 return static_cast<const VideoContentDescription*>(
2541 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2542}
2543
2544const DataContentDescription* GetFirstDataContentDescription(
2545 const SessionDescription* sdesc) {
2546 return static_cast<const DataContentDescription*>(
2547 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2548}
2549
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002550//
2551// Non-const versions of the above functions.
2552//
2553
Steve Anton36b29d12017-10-30 09:57:42 -07002554ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002555 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002556 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002557 if (IsMediaContentOfType(&content, media_type)) {
2558 return &content;
2559 }
2560 }
2561 return nullptr;
2562}
2563
Steve Anton36b29d12017-10-30 09:57:42 -07002564ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002565 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2566}
2567
Steve Anton36b29d12017-10-30 09:57:42 -07002568ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002569 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2570}
2571
Steve Anton36b29d12017-10-30 09:57:42 -07002572ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002573 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2574}
2575
Steve Antonad7bffc2018-01-22 10:21:56 -08002576ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2577 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002578 if (sdesc == nullptr) {
2579 return nullptr;
2580 }
2581
Steve Anton36b29d12017-10-30 09:57:42 -07002582 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002583}
2584
2585ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2586 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2587}
2588
2589ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2590 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2591}
2592
2593ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2594 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2595}
2596
2597MediaContentDescription* GetFirstMediaContentDescription(
2598 SessionDescription* sdesc,
2599 MediaType media_type) {
2600 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002601 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002602}
2603
2604AudioContentDescription* GetFirstAudioContentDescription(
2605 SessionDescription* sdesc) {
2606 return static_cast<AudioContentDescription*>(
2607 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2608}
2609
2610VideoContentDescription* GetFirstVideoContentDescription(
2611 SessionDescription* sdesc) {
2612 return static_cast<VideoContentDescription*>(
2613 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2614}
2615
2616DataContentDescription* GetFirstDataContentDescription(
2617 SessionDescription* sdesc) {
2618 return static_cast<DataContentDescription*>(
2619 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2620}
2621
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622} // namespace cricket