blob: 2e2f0cdc3631b4dddd476232ed9470930a8b21e2 [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
deadbeef67cf2c12016-04-13 10:07:16 -070013#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve 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) {
188 auto it = std::find_if(
189 cryptos.begin(), cryptos.end(),
190 [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
191 if (it == cryptos.end()) {
192 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700194 *crypto_out = *it;
195 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000196}
197
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700198// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
199// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700200void GetSupportedAudioSdesCryptoSuites(
201 const webrtc::CryptoOptions& crypto_options,
202 std::vector<int>* crypto_suites) {
203 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700204 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
205 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
206 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700207 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700208 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
209 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800210 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211}
212
deadbeef7914b8c2017-04-21 03:23:33 -0700213void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700214 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800215 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700216 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
217 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218}
219
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700220void GetSupportedVideoSdesCryptoSuites(
221 const webrtc::CryptoOptions& crypto_options,
222 std::vector<int>* crypto_suites) {
223 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
225 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
226 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800227 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228}
229
deadbeef7914b8c2017-04-21 03:23:33 -0700230void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700231 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800232 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700233 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
234 crypto_options, crypto_suite_names);
235}
236
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700237void GetSupportedDataSdesCryptoSuites(
238 const webrtc::CryptoOptions& crypto_options,
239 std::vector<int>* crypto_suites) {
240 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700241 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
242 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
243 }
244 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
245}
246
247void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700248 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700249 std::vector<std::string>* crypto_suite_names) {
250 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
251 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800252}
253
jbauchcb560652016-08-04 05:20:32 -0700254// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700255// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
256// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700257// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258static bool SelectCrypto(const MediaContentDescription* offer,
259 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700260 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700261 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
263 const CryptoParamsVec& cryptos = offer->cryptos();
264
Steve Anton3a66edf2018-09-10 12:57:37 -0700265 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700266 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700267 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
268 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
269 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700270 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700271 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 }
273 }
274 return false;
275}
276
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000277// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800278static StreamParamsVec GetCurrentStreamParams(
279 const std::vector<const ContentInfo*>& active_local_contents) {
280 StreamParamsVec stream_params;
281 for (const ContentInfo* content : active_local_contents) {
282 for (const StreamParams& params : content->media_description()->streams()) {
283 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284 }
285 }
Steve Anton5c72e712018-12-10 14:25:30 -0800286 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287}
288
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000289// Filters the data codecs for the data channel type.
290void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
291 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700292 const char* codec_name =
293 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700294 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
295 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200296 return absl::EqualsIgnoreCase(codec.name,
297 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700298 }),
299 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000300}
301
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302template <typename IdStruct>
303class UsedIds {
304 public:
305 UsedIds(int min_allowed_id, int max_allowed_id)
306 : min_allowed_id_(min_allowed_id),
307 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200308 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309
310 // Loops through all Id in |ids| and changes its id if it is
311 // already in use by another IdStruct. Call this methods with all Id
312 // in a session description to make sure no duplicate ids exists.
313 // Note that typename Id must be a type of IdStruct.
314 template <typename Id>
315 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700316 for (const Id& id : *ids) {
317 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318 }
319 }
320
321 // Finds and sets an unused id if the |idstruct| id is already in use.
322 void FindAndSetIdUsed(IdStruct* idstruct) {
323 const int original_id = idstruct->id;
324 int new_id = idstruct->id;
325
326 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
327 // If the original id is not in range - this is an id that can't be
328 // dynamically changed.
329 return;
330 }
331
332 if (IsIdUsed(original_id)) {
333 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100334 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
335 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336 idstruct->id = new_id;
337 }
338 SetIdUsed(new_id);
339 }
340
341 private:
342 // Returns the first unused id in reverse order.
343 // This hopefully reduce the risk of more collisions. We want to change the
344 // default ids as little as possible.
345 int FindUnusedId() {
346 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
347 --next_id_;
348 }
nisseede5da42017-01-12 05:15:36 -0800349 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 return next_id_;
351 }
352
Yves Gerey665174f2018-06-19 15:03:05 +0200353 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354
Yves Gerey665174f2018-06-19 15:03:05 +0200355 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356
357 const int min_allowed_id_;
358 const int max_allowed_id_;
359 int next_id_;
360 std::set<int> id_set_;
361};
362
363// Helper class used for finding duplicate RTP payload types among audio, video
364// and data codecs. When bundle is used the payload types may not collide.
365class UsedPayloadTypes : public UsedIds<Codec> {
366 public:
367 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200368 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369
370 private:
371 static const int kDynamicPayloadTypeMin = 96;
372 static const int kDynamicPayloadTypeMax = 127;
373};
374
375// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200376// audio and video extensions. Only applies to one-byte header extensions at the
377// moment. ids > 14 will always be reported as available.
378// TODO(kron): This class needs to be refactored when we start to send two-byte
379// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700380class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000381 public:
382 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200383 : UsedIds<webrtc::RtpExtension>(
384 webrtc::RtpExtension::kMinId,
385 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386
387 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388};
389
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800390static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
391 const SenderOptions& sender,
392 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800393 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800394 bool include_flexfec_stream,
395 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800396 StreamParams result;
397 result.id = sender.track_id;
398
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800399 // TODO(brandtr): Update when we support multistream protection.
400 if (include_flexfec_stream && sender.num_sim_layers > 1) {
401 include_flexfec_stream = false;
402 RTC_LOG(LS_WARNING)
403 << "Our FlexFEC implementation only supports protecting "
404 "a single media streams. This session has multiple "
405 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800406 }
407
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800408 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
409 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800411 result.cname = rtcp_cname;
412 result.set_stream_ids(sender.stream_ids);
413
414 return result;
415}
416
417static bool ValidateSimulcastLayers(
418 const std::vector<RidDescription>& rids,
419 const SimulcastLayerList& simulcast_layers) {
420 std::vector<SimulcastLayer> all_layers = simulcast_layers.GetAllLayers();
421 return std::all_of(all_layers.begin(), all_layers.end(),
422 [&rids](const SimulcastLayer& layer) {
423 return std::find_if(rids.begin(), rids.end(),
424 [&layer](const RidDescription& rid) {
425 return rid.rid == layer.rid;
426 }) != rids.end();
427 });
428}
429
430static StreamParams CreateStreamParamsForNewSenderWithRids(
431 const SenderOptions& sender,
432 const std::string& rtcp_cname) {
433 RTC_DCHECK(!sender.rids.empty());
434 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
435 << "RIDs are the compliant way to indicate simulcast.";
436 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
437 StreamParams result;
438 result.id = sender.track_id;
439 result.cname = rtcp_cname;
440 result.set_stream_ids(sender.stream_ids);
441
442 // More than one rid should be signaled.
443 if (sender.rids.size() > 1) {
444 result.set_rids(sender.rids);
445 }
446
447 return result;
448}
449
450// Adds SimulcastDescription if indicated by the media description options.
451// MediaContentDescription should already be set up with the send rids.
452static void AddSimulcastToMediaDescription(
453 const MediaDescriptionOptions& media_description_options,
454 MediaContentDescription* description) {
455 RTC_DCHECK(description);
456
457 // Check if we are using RIDs in this scenario.
458 if (std::all_of(
459 description->streams().begin(), description->streams().end(),
460 [](const StreamParams& params) { return !params.has_rids(); })) {
461 return;
462 }
463
464 RTC_DCHECK_EQ(1, description->streams().size())
465 << "RIDs are only supported in Unified Plan semantics.";
466 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
467 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
468 description->type() == MediaType::MEDIA_TYPE_VIDEO);
469
470 // One RID or less indicates that simulcast is not needed.
471 if (description->streams()[0].rids().size() <= 1) {
472 return;
473 }
474
475 RTC_DCHECK(!media_description_options.receive_rids.empty());
476 RTC_DCHECK(ValidateSimulcastLayers(
477 media_description_options.receive_rids,
478 media_description_options.receive_simulcast_layers));
479 StreamParams receive_stream;
480 receive_stream.set_rids(media_description_options.receive_rids);
481 description->set_receive_stream(receive_stream);
482
483 SimulcastDescription simulcast;
484 simulcast.send_layers() =
485 media_description_options.sender_options[0].simulcast_layers;
486 simulcast.receive_layers() =
487 media_description_options.receive_simulcast_layers;
488 description->set_simulcast_description(simulcast);
489}
490
zhihuang1c378ed2017-08-17 14:10:50 -0700491// Adds a StreamParams for each SenderOptions in |sender_options| to
492// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493// |current_params| - All currently known StreamParams of any media type.
494template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700495static bool AddStreamParams(
496 const std::vector<SenderOptions>& sender_options,
497 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800498 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700499 StreamParamsVec* current_streams,
500 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700501 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700502 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700503 return true;
504 }
505
Noah Richards2e7a0982015-05-18 14:02:54 -0700506 const bool include_rtx_streams =
507 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508
brandtr03d5fb12016-11-22 03:37:59 -0800509 const bool include_flexfec_stream =
510 ContainsFlexfecCodec(content_description->codecs());
511
zhihuang1c378ed2017-08-17 14:10:50 -0700512 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 // groupid is empty for StreamParams generated using
514 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700515 StreamParams* param =
516 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000517 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700518 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800519 StreamParams stream_param =
520 sender.rids.empty()
521 ?
522 // Signal SSRCs and legacy simulcast (if requested).
523 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800524 sender, rtcp_cname, include_rtx_streams,
525 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800526 :
527 // Signal RIDs and spec-compliant simulcast (if requested).
528 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
529
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 content_description->AddStream(stream_param);
531
532 // Store the new StreamParams in current_streams.
533 // This is necessary so that we can use the CNAME for other media types.
534 current_streams->push_back(stream_param);
535 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700536 // Use existing generated SSRCs/groups, but update the sync_label if
537 // necessary. This may be needed if a MediaStreamTrack was moved from one
538 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800539 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000540 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 }
542 }
543 return true;
544}
545
546// Updates the transport infos of the |sdesc| according to the given
547// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800548// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
549// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
551 SessionDescription* sdesc) {
552 // The bundle should not be empty.
553 if (!sdesc || !bundle_group.FirstContentName()) {
554 return false;
555 }
556
557 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700558 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 const TransportInfo* selected_transport_info =
560 sdesc->GetTransportInfoByName(selected_content_name);
561 if (!selected_transport_info) {
562 return false;
563 }
564
565 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700566 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700568 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800570 ConnectionRole selected_connection_role =
571 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700572 for (TransportInfo& transport_info : sdesc->transport_infos()) {
573 if (bundle_group.HasContentName(transport_info.content_name) &&
574 transport_info.content_name != selected_content_name) {
575 transport_info.description.ice_ufrag = selected_ufrag;
576 transport_info.description.ice_pwd = selected_pwd;
577 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 }
579 }
580 return true;
581}
582
583// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
584// sets it to |cryptos|.
585static bool GetCryptosByName(const SessionDescription* sdesc,
586 const std::string& content_name,
587 CryptoParamsVec* cryptos) {
588 if (!sdesc || !cryptos) {
589 return false;
590 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800592 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 return false;
594 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800595 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 return true;
597}
598
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
600// which are not available in |filter|.
601static void PruneCryptos(const CryptoParamsVec& filter,
602 CryptoParamsVec* target_cryptos) {
603 if (!target_cryptos) {
604 return;
605 }
tzik21995802018-04-26 17:38:28 +0900606
607 target_cryptos->erase(
608 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
609 // Returns true if the |crypto|'s cipher_suite is not
610 // found in |filter|.
611 [&filter](const CryptoParams& crypto) {
612 for (const CryptoParams& entry : filter) {
613 if (entry.cipher_suite == crypto.cipher_suite)
614 return false;
615 }
616 return true;
617 }),
618 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619}
620
Steve Antonfa2260d2017-12-28 16:38:23 -0800621bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800622 return protocol.empty() ||
623 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
624}
625
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626static bool IsRtpContent(SessionDescription* sdesc,
627 const std::string& content_name) {
628 bool is_rtp = false;
629 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800630 if (content && content->media_description()) {
631 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 }
633 return is_rtp;
634}
635
636// Updates the crypto parameters of the |sdesc| according to the given
637// |bundle_group|. The crypto parameters of all the contents within the
638// |bundle_group| should be updated to use the common subset of the
639// available cryptos.
640static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
641 SessionDescription* sdesc) {
642 // The bundle should not be empty.
643 if (!sdesc || !bundle_group.FirstContentName()) {
644 return false;
645 }
646
wu@webrtc.org78187522013-10-07 23:32:02 +0000647 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 // Get the common cryptos.
649 const ContentNames& content_names = bundle_group.content_names();
650 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700651 bool first = true;
652 for (const std::string& content_name : content_names) {
653 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 continue;
655 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000656 // The common cryptos are needed if any of the content does not have DTLS
657 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700658 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000659 common_cryptos_needed = true;
660 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700661 if (first) {
662 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700664 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 return false;
666 }
667 if (common_cryptos.empty()) {
668 // If there's no crypto params, we should just return.
669 return true;
670 }
671 } else {
672 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700673 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000674 return false;
675 }
676 PruneCryptos(cryptos, &common_cryptos);
677 }
678 }
679
wu@webrtc.org78187522013-10-07 23:32:02 +0000680 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 return false;
682 }
683
684 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700685 for (const std::string& content_name : content_names) {
686 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 continue;
688 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700689 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800691 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 if (!media_desc) {
693 return false;
694 }
695 media_desc->set_cryptos(common_cryptos);
696 }
697 }
698 return true;
699}
700
Steve Anton5c72e712018-12-10 14:25:30 -0800701static std::vector<const ContentInfo*> GetActiveContents(
702 const SessionDescription& description,
703 const MediaSessionOptions& session_options) {
704 std::vector<const ContentInfo*> active_contents;
705 for (size_t i = 0; i < description.contents().size(); ++i) {
706 RTC_DCHECK_LT(i, session_options.media_description_options.size());
707 const ContentInfo& content = description.contents()[i];
708 const MediaDescriptionOptions& media_options =
709 session_options.media_description_options[i];
710 if (!content.rejected && !media_options.stopped &&
711 content.name == media_options.mid) {
712 active_contents.push_back(&content);
713 }
714 }
715 return active_contents;
716}
717
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718template <class C>
719static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800720 for (const auto& codec : codecs) {
721 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 return true;
723 }
724 }
725 return false;
726}
727
728template <class C>
729static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200730 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731}
732
brandtr03d5fb12016-11-22 03:37:59 -0800733template <class C>
734static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
735 for (const auto& codec : codecs) {
736 if (IsFlexfecCodec(codec)) {
737 return true;
738 }
739 }
740 return false;
741}
742
743template <class C>
744static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200745 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800746}
747
zhihuang1c378ed2017-08-17 14:10:50 -0700748// Create a media content to be offered for the given |sender_options|,
749// according to the given options.rtcp_mux, session_options.is_muc, codecs,
750// secure_transport, crypto, and current_streams. If we don't currently have
751// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
752// created (according to crypto_suites). The created content is added to the
753// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754template <class C>
755static bool CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800756 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700757 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000759 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 const CryptoParamsVec* current_cryptos,
761 const std::vector<std::string>& crypto_suites,
762 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800763 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 StreamParamsVec* current_streams,
765 MediaContentDescriptionImpl<C>* offer) {
766 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767
zhihuang1c378ed2017-08-17 14:10:50 -0700768 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700769 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
770 offer->set_rtcp_reduced_size(true);
771 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 offer->set_rtp_header_extensions(rtp_extensions);
773
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800774 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800775 session_options.rtcp_cname, ssrc_generator,
776 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 return false;
778 }
779
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800780 AddSimulcastToMediaDescription(media_description_options, offer);
781
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 if (secure_policy != SEC_DISABLED) {
783 if (current_cryptos) {
784 AddMediaCryptos(*current_cryptos, offer);
785 }
786 if (offer->cryptos().empty()) {
787 if (!CreateMediaCryptos(crypto_suites, offer)) {
788 return false;
789 }
790 }
791 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792
deadbeef7af91dd2016-12-13 11:29:11 -0800793 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 return false;
795 }
796 return true;
797}
798
799template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000800static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800801 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000802 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800803 const int codec2_id) {
804 const C* codec1 = FindCodecById(codecs1, codec1_id);
805 const C* codec2 = FindCodecById(codecs2, codec2_id);
806 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000807}
808
809template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810static void NegotiateCodecs(const std::vector<C>& local_codecs,
811 const std::vector<C>& offered_codecs,
812 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800813 for (const C& ours : local_codecs) {
814 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700815 // Note that we intentionally only find one matching codec for each of our
816 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800817 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
818 C negotiated = ours;
819 negotiated.IntersectFeedbackParams(theirs);
820 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800821 const auto apt_it =
822 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800823 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800824 RTC_DCHECK(apt_it != theirs.params.end());
825 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 }
Niels Möller039743e2018-10-23 10:07:25 +0200827 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800828 webrtc::H264::GenerateProfileLevelIdForAnswer(
829 ours.params, theirs.params, &negotiated.params);
830 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800831 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700832 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800833 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 }
835 }
deadbeef67cf2c12016-04-13 10:07:16 -0700836 // RFC3264: Although the answerer MAY list the formats in their desired
837 // order of preference, it is RECOMMENDED that unless there is a
838 // specific reason, the answerer list formats in the same relative order
839 // they were present in the offer.
840 std::unordered_map<int, int> payload_type_preferences;
841 int preference = static_cast<int>(offered_codecs.size() + 1);
842 for (const C& codec : offered_codecs) {
843 payload_type_preferences[codec.id] = preference--;
844 }
845 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
846 [&payload_type_preferences](const C& a, const C& b) {
847 return payload_type_preferences[a.id] >
848 payload_type_preferences[b.id];
849 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850}
851
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852// Finds a codec in |codecs2| that matches |codec_to_match|, which is
853// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
854// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800856static bool FindMatchingCodec(const std::vector<C>& codecs1,
857 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858 const C& codec_to_match,
859 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700860 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
861 // codecs' associated codecs correctly. If not, that's a programming error.
862 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
863 [&codec_to_match](const C& codec) {
864 return &codec == &codec_to_match;
865 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800866 for (const C& potential_match : codecs2) {
867 if (potential_match.Matches(codec_to_match)) {
868 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800869 int apt_value_1 = 0;
870 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800871 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
872 &apt_value_1) ||
873 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
874 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100875 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800876 continue;
877 }
878 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
879 apt_value_2)) {
880 continue;
881 }
882 }
883 if (found_codec) {
884 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885 }
886 return true;
887 }
888 }
889 return false;
890}
891
zhihuang1c378ed2017-08-17 14:10:50 -0700892// Find the codec in |codec_list| that |rtx_codec| is associated with.
893template <class C>
894static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
895 const C& rtx_codec) {
896 std::string associated_pt_str;
897 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
898 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100899 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
900 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700901 return nullptr;
902 }
903
904 int associated_pt;
905 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100906 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
907 << " of RTX codec " << rtx_codec.name
908 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700909 return nullptr;
910 }
911
912 // Find the associated reference codec for the reference RTX codec.
913 const C* associated_codec = FindCodecById(codec_list, associated_pt);
914 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100915 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
916 << associated_pt << " for RTX codec " << rtx_codec.name
917 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700918 }
919 return associated_codec;
920}
921
922// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923// already exist in |offered_codecs| and ensure the payload types don't
924// collide.
925template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700926static void MergeCodecs(const std::vector<C>& reference_codecs,
927 std::vector<C>* offered_codecs,
928 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800930 for (const C& reference_codec : reference_codecs) {
931 if (!IsRtxCodec(reference_codec) &&
932 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
933 reference_codec, nullptr)) {
934 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 used_pltypes->FindAndSetIdUsed(&codec);
936 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 }
938 }
939
940 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800941 for (const C& reference_codec : reference_codecs) {
942 if (IsRtxCodec(reference_codec) &&
943 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
944 reference_codec, nullptr)) {
945 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700946 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700947 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700948 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700949 continue;
950 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800951 // Find a codec in the offered list that matches the reference codec.
952 // Its payload type may be different than the reference codec.
953 C matching_codec;
954 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800955 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100956 RTC_LOG(LS_WARNING)
957 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800958 continue;
959 }
960
961 rtx_codec.params[kCodecParamAssociatedPayloadType] =
962 rtc::ToString(matching_codec.id);
963 used_pltypes->FindAndSetIdUsed(&rtx_codec);
964 offered_codecs->push_back(rtx_codec);
965 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966 }
967}
968
zhihuang1c378ed2017-08-17 14:10:50 -0700969static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
970 const webrtc::RtpExtension& ext_to_match,
971 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700972 auto it =
973 std::find_if(extensions.begin(), extensions.end(),
974 [&ext_to_match](const webrtc::RtpExtension& extension) {
975 // We assume that all URIs are given in a canonical
976 // format.
977 return extension.uri == ext_to_match.uri &&
978 extension.encrypt == ext_to_match.encrypt;
979 });
980 if (it == extensions.end()) {
981 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700982 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700983 if (found_extension) {
984 *found_extension = *it;
985 }
986 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700987}
988
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700990 const webrtc::RtpExtension& ext_to_match,
991 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700992 // We assume that all URIs are given in a canonical format.
993 const webrtc::RtpExtension* found =
994 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
995 ext_to_match.uri);
996 if (!found) {
997 return false;
998 }
999 if (found_extension) {
1000 *found_extension = *found;
1001 }
1002 return true;
1003}
1004
1005static bool FindByUriWithEncryptionPreference(
1006 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001007 const webrtc::RtpExtension& ext_to_match,
1008 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001009 webrtc::RtpExtension* found_extension) {
1010 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001011 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001013 if (extension.uri == ext_to_match.uri) {
1014 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001015 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001016 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001017 }
1018 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001020 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001021 }
1022 }
jbauch5869f502017-06-29 12:31:36 -07001023 if (unencrypted_extension) {
1024 if (found_extension) {
1025 *found_extension = *unencrypted_extension;
1026 }
1027 return true;
1028 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 return false;
1030}
1031
zhihuang1c378ed2017-08-17 14:10:50 -07001032// Adds all extensions from |reference_extensions| to |offered_extensions| that
1033// don't already exist in |offered_extensions| and ensure the IDs don't
1034// collide. If an extension is added, it's also added to |regular_extensions| or
1035// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1036// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1037// |offered_extensions| is for either audio or video while |regular_extensions|
1038// and |encrypted_extensions| are used for both audio and video. There could be
1039// overlap between audio extensions and video extensions.
1040static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1041 RtpHeaderExtensions* offered_extensions,
1042 RtpHeaderExtensions* regular_extensions,
1043 RtpHeaderExtensions* encrypted_extensions,
1044 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001045 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001046 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1047 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001048 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001049 if (reference_extension.encrypt) {
1050 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1051 &existing)) {
1052 offered_extensions->push_back(existing);
1053 } else {
1054 used_ids->FindAndSetIdUsed(&reference_extension);
1055 encrypted_extensions->push_back(reference_extension);
1056 offered_extensions->push_back(reference_extension);
1057 }
olka3c747662017-08-17 06:50:32 -07001058 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001059 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1060 &existing)) {
1061 offered_extensions->push_back(existing);
1062 } else {
1063 used_ids->FindAndSetIdUsed(&reference_extension);
1064 regular_extensions->push_back(reference_extension);
1065 offered_extensions->push_back(reference_extension);
1066 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001067 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 }
1069 }
1070}
1071
jbauch5869f502017-06-29 12:31:36 -07001072static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1073 RtpHeaderExtensions* all_extensions,
1074 UsedRtpHeaderExtensionIds* used_ids) {
1075 RtpHeaderExtensions encrypted_extensions;
1076 for (const webrtc::RtpExtension& extension : *extensions) {
1077 webrtc::RtpExtension existing;
1078 // Don't add encrypted extensions again that were already included in a
1079 // previous offer or regular extensions that are also included as encrypted
1080 // extensions.
1081 if (extension.encrypt ||
1082 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1083 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001084 &existing) &&
1085 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001086 continue;
1087 }
1088
1089 if (FindByUri(*all_extensions, extension, &existing)) {
1090 encrypted_extensions.push_back(existing);
1091 } else {
1092 webrtc::RtpExtension encrypted(extension);
1093 encrypted.encrypt = true;
1094 used_ids->FindAndSetIdUsed(&encrypted);
1095 all_extensions->push_back(encrypted);
1096 encrypted_extensions.push_back(encrypted);
1097 }
1098 }
1099 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001100 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001101}
1102
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103static void NegotiateRtpHeaderExtensions(
1104 const RtpHeaderExtensions& local_extensions,
1105 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001106 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001107 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001108 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001109 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001110 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001111 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001112 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001113 // We respond with their RTP header extension id.
1114 negotiated_extenstions->push_back(theirs);
1115 }
1116 }
1117}
1118
1119static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001120 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1121 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001122 return absl::EqualsIgnoreCase(
1123 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001124 }),
1125 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126}
1127
zhihuang1c378ed2017-08-17 14:10:50 -07001128// Create a media content to be answered for the given |sender_options|
1129// according to the given session_options.rtcp_mux, session_options.streams,
1130// codecs, crypto, and current_streams. If we don't currently have crypto (in
1131// current_cryptos) and it is enabled (in secure_policy), crypto is created
1132// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1133// negotiated with the offer. If the negotiation fails, this method returns
1134// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135template <class C>
1136static bool CreateMediaContentAnswer(
1137 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001138 const MediaDescriptionOptions& media_description_options,
1139 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001141 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001142 const CryptoParamsVec* current_cryptos,
1143 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001144 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001145 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001146 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147 bool bundle_enabled,
1148 MediaContentDescriptionImpl<C>* answer) {
1149 std::vector<C> negotiated_codecs;
1150 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1151 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001153
Johannes Kron9581bc42018-10-23 10:17:39 +02001154 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001156 NegotiateRtpHeaderExtensions(
1157 local_rtp_extenstions, offer->rtp_header_extensions(),
1158 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001159 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1160
zhihuang1c378ed2017-08-17 14:10:50 -07001161 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001162 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1163 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1164 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165
1166 if (sdes_policy != SEC_DISABLED) {
1167 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001168 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1169 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001170 if (current_cryptos) {
1171 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1172 }
1173 answer->AddCrypto(crypto);
1174 }
1175 }
1176
deadbeef7af91dd2016-12-13 11:29:11 -08001177 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 return false;
1179 }
1180
zhihuang1c378ed2017-08-17 14:10:50 -07001181 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001182 session_options.rtcp_cname, ssrc_generator,
1183 current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001184 return false; // Something went seriously wrong.
1185 }
1186
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001187 AddSimulcastToMediaDescription(media_description_options, answer);
1188
Steve Anton4e70a722017-11-28 14:57:10 -08001189 answer->set_direction(NegotiateRtpTransceiverDirection(
1190 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 return true;
1192}
1193
1194static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001195 const std::string& protocol,
1196 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001197 // Since not all applications serialize and deserialize the media protocol,
1198 // we will have to accept |protocol| to be empty.
1199 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200 return true;
1201 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001202
zhihuangcf5b37c2016-05-05 11:44:35 -07001203 if (type == MEDIA_TYPE_DATA) {
1204 // Check for SCTP, but also for RTP for RTP-based data channels.
1205 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1206 if (secure_transport) {
1207 // Most likely scenarios first.
1208 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1209 IsPlainRtp(protocol);
1210 } else {
1211 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1212 }
1213 }
1214
1215 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1216 // JSEP specifies.
1217 if (secure_transport) {
1218 // Most likely scenarios first.
1219 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1220 } else {
1221 return IsPlainRtp(protocol);
1222 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223}
1224
1225static void SetMediaProtocol(bool secure_transport,
1226 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001227 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001229 else if (secure_transport)
1230 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 else
1232 desc->set_protocol(kMediaProtocolAvpf);
1233}
1234
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001235// Gets the TransportInfo of the given |content_name| from the
1236// |current_description|. If doesn't exist, returns a new one.
1237static const TransportDescription* GetTransportDescription(
1238 const std::string& content_name,
1239 const SessionDescription* current_description) {
1240 const TransportDescription* desc = NULL;
1241 if (current_description) {
1242 const TransportInfo* info =
1243 current_description->GetTransportInfoByName(content_name);
1244 if (info) {
1245 desc = &info->description;
1246 }
1247 }
1248 return desc;
1249}
1250
1251// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001252static bool IsDtlsActive(const ContentInfo* content,
1253 const SessionDescription* current_description) {
1254 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001255 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001256 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001257
zhihuang1c378ed2017-08-17 14:10:50 -07001258 size_t msection_index = content - &current_description->contents()[0];
1259
1260 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001261 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001262 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001263
zhihuang1c378ed2017-08-17 14:10:50 -07001264 return current_description->transport_infos()[msection_index]
1265 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001266}
1267
Steve Anton8ffb9c32017-08-31 15:45:38 -07001268void MediaDescriptionOptions::AddAudioSender(
1269 const std::string& track_id,
1270 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001271 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001272 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001273}
1274
Steve Anton8ffb9c32017-08-31 15:45:38 -07001275void MediaDescriptionOptions::AddVideoSender(
1276 const std::string& track_id,
1277 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001278 const std::vector<RidDescription>& rids,
1279 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001280 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001281 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001282 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1283 << "RIDs are the compliant way to indicate simulcast.";
1284 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1285 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1286 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001287}
1288
zhihuang1c378ed2017-08-17 14:10:50 -07001289void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1290 const std::string& stream_id) {
1291 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001292 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1293 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001294 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295}
1296
Steve Anton8ffb9c32017-08-31 15:45:38 -07001297void MediaDescriptionOptions::AddSenderInternal(
1298 const std::string& track_id,
1299 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001300 const std::vector<RidDescription>& rids,
1301 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001302 int num_sim_layers) {
1303 // TODO(steveanton): Support any number of stream ids.
1304 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001305 SenderOptions options;
1306 options.track_id = track_id;
1307 options.stream_ids = stream_ids;
1308 options.simulcast_layers = simulcast_layers;
1309 options.rids = rids;
1310 options.num_sim_layers = num_sim_layers;
1311 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312}
1313
zhihuang1c378ed2017-08-17 14:10:50 -07001314bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1315 return std::find_if(media_description_options.begin(),
1316 media_description_options.end(),
1317 [type](const MediaDescriptionOptions& t) {
1318 return t.type == type;
1319 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001320}
1321
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001323 const TransportDescriptionFactory* transport_desc_factory,
1324 rtc::UniqueRandomIdGenerator* ssrc_generator)
1325 : ssrc_generator_(ssrc_generator),
1326 transport_desc_factory_(transport_desc_factory) {
1327 RTC_DCHECK(ssrc_generator_);
1328}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329
1330MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1331 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001332 const TransportDescriptionFactory* transport_desc_factory,
1333 rtc::UniqueRandomIdGenerator* ssrc_generator)
1334 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001335 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1336 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001338 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1340 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001341 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001342}
1343
ossudedfd282016-06-14 07:12:39 -07001344const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1345 const {
ossu075af922016-06-14 03:29:38 -07001346 return audio_sendrecv_codecs_;
1347}
1348
1349const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1350 return audio_send_codecs_;
1351}
1352
1353const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1354 return audio_recv_codecs_;
1355}
1356
1357void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001358 const AudioCodecs& send_codecs,
1359 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001360 audio_send_codecs_ = send_codecs;
1361 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001362 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001363}
1364
Amit Hilbuch77938e62018-12-21 09:23:38 -08001365static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1366 RTC_DCHECK(extensions);
1367 // Unified Plan also offers the MID and RID header extensions.
1368 extensions->push_back(webrtc::RtpExtension(
1369 webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
1370 extensions->push_back(webrtc::RtpExtension(
1371 webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRidDefaultId));
1372 extensions->push_back(
1373 webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri,
1374 webrtc::RtpExtension::kRepairedRidDefaultId));
1375}
1376
1377RtpHeaderExtensions
1378MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1379 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1380 if (is_unified_plan_) {
1381 AddUnifiedPlanExtensions(&extensions);
1382 }
1383
1384 return extensions;
1385}
1386
1387RtpHeaderExtensions
1388MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1389 RtpHeaderExtensions extensions = video_rtp_extensions_;
1390 if (is_unified_plan_) {
1391 AddUnifiedPlanExtensions(&extensions);
1392 }
1393
1394 return extensions;
1395}
1396
Steve Anton6fe1fba2018-12-11 10:15:23 -08001397std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001398 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001400 // Must have options for each existing section.
1401 if (current_description) {
1402 RTC_DCHECK_LE(current_description->contents().size(),
1403 session_options.media_description_options.size());
1404 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001405
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001406 IceCredentialsIterator ice_credentials(
1407 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001408
1409 std::vector<const ContentInfo*> current_active_contents;
1410 if (current_description) {
1411 current_active_contents =
1412 GetActiveContents(*current_description, session_options);
1413 }
1414
1415 StreamParamsVec current_streams =
1416 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001417
zhihuang1c378ed2017-08-17 14:10:50 -07001418 AudioCodecs offer_audio_codecs;
1419 VideoCodecs offer_video_codecs;
1420 DataCodecs offer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001421 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001422 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001423
zhihuang1c378ed2017-08-17 14:10:50 -07001424 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001425 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001426 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427 }
zhihuang1c378ed2017-08-17 14:10:50 -07001428 FilterDataCodecs(&offer_data_codecs,
1429 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001430
1431 RtpHeaderExtensions audio_rtp_extensions;
1432 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001433 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1434 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001435
Steve Anton5c72e712018-12-10 14:25:30 -08001436 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001437
zhihuang1c378ed2017-08-17 14:10:50 -07001438 // Iterate through the media description options, matching with existing media
1439 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001440 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001441 for (const MediaDescriptionOptions& media_description_options :
1442 session_options.media_description_options) {
1443 const ContentInfo* current_content = nullptr;
1444 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001445 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001446 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001447 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001448 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001449 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001450 media_description_options.type));
1451 }
1452 switch (media_description_options.type) {
1453 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001454 if (!AddAudioContentForOffer(
1455 media_description_options, session_options, current_content,
1456 current_description, audio_rtp_extensions, offer_audio_codecs,
1457 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001458 return nullptr;
1459 }
1460 break;
1461 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001462 if (!AddVideoContentForOffer(
1463 media_description_options, session_options, current_content,
1464 current_description, video_rtp_extensions, offer_video_codecs,
1465 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001466 return nullptr;
1467 }
1468 break;
1469 case MEDIA_TYPE_DATA:
1470 if (!AddDataContentForOffer(media_description_options, session_options,
1471 current_content, current_description,
1472 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001473 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001474 return nullptr;
1475 }
1476 break;
1477 default:
1478 RTC_NOTREACHED();
1479 }
1480 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481 }
1482
1483 // Bundle the contents together, if we've been asked to do so, and update any
1484 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001485 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001486 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001487 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001488 if (content.rejected) {
1489 continue;
1490 }
zhihuang1c378ed2017-08-17 14:10:50 -07001491 // TODO(deadbeef): There are conditions that make bundling two media
1492 // descriptions together illegal. For example, they use the same payload
1493 // type to represent different codecs, or same IDs for different header
1494 // extensions. We need to detect this and not try to bundle those media
1495 // descriptions together.
1496 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001497 }
Steve Anton2bed3972019-01-04 17:04:30 -08001498 if (!offer_bundle.content_names().empty()) {
1499 offer->AddGroup(offer_bundle);
1500 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1501 RTC_LOG(LS_ERROR)
1502 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1503 return nullptr;
1504 }
1505 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1506 RTC_LOG(LS_ERROR)
1507 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1508 return nullptr;
1509 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001510 }
1511 }
Steve Antone831b8c2018-02-01 12:22:16 -08001512
1513 // The following determines how to signal MSIDs to ensure compatibility with
1514 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001515 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001516 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1517 // Plan answerers will look at a=msid and Plan B answerers will look at the
1518 // a=ssrc MSID line.
1519 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1520 cricket::kMsidSignalingSsrcAttribute);
1521 } else {
1522 // Plan B always signals MSID using a=ssrc lines.
1523 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1524 }
1525
Johannes Kron89f874e2018-11-12 10:25:48 +01001526 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1527
Steve Anton6fe1fba2018-12-11 10:15:23 -08001528 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001529}
1530
Steve Anton6fe1fba2018-12-11 10:15:23 -08001531std::unique_ptr<SessionDescription>
1532MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001533 const SessionDescription* offer,
1534 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001536 if (!offer) {
1537 return nullptr;
1538 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001539
Steve Anton5c72e712018-12-10 14:25:30 -08001540 // Must have options for exactly as many sections as in the offer.
1541 RTC_DCHECK_EQ(offer->contents().size(),
1542 session_options.media_description_options.size());
1543
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001544 IceCredentialsIterator ice_credentials(
1545 session_options.pooled_ice_credentials);
1546
Steve Anton5c72e712018-12-10 14:25:30 -08001547 std::vector<const ContentInfo*> current_active_contents;
1548 if (current_description) {
1549 current_active_contents =
1550 GetActiveContents(*current_description, session_options);
1551 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001552
Steve Anton5c72e712018-12-10 14:25:30 -08001553 StreamParamsVec current_streams =
1554 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001555
zhihuang1c378ed2017-08-17 14:10:50 -07001556 // Get list of all possible codecs that respects existing payload type
1557 // mappings and uses a single payload type space.
1558 //
1559 // Note that these lists may be further filtered for each m= section; this
1560 // step is done just to establish the payload type mappings shared by all
1561 // sections.
1562 AudioCodecs answer_audio_codecs;
1563 VideoCodecs answer_video_codecs;
1564 DataCodecs answer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001565 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001566 &answer_video_codecs, &answer_data_codecs);
1567
1568 if (!session_options.vad_enabled) {
1569 // If application doesn't want CN codecs in answer.
1570 StripCNCodecs(&answer_audio_codecs);
1571 }
1572 FilterDataCodecs(&answer_data_codecs,
1573 session_options.data_channel_type == DCT_SCTP);
1574
Steve Anton5c72e712018-12-10 14:25:30 -08001575 auto answer = absl::make_unique<SessionDescription>();
1576
1577 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1578 // group in the answer with the appropriate content names.
1579 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1580 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1581 // Transport info shared by the bundle group.
1582 std::unique_ptr<TransportInfo> bundle_transport;
1583
1584 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1585
zhihuang1c378ed2017-08-17 14:10:50 -07001586 // Iterate through the media description options, matching with existing
1587 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001588 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001589 for (const MediaDescriptionOptions& media_description_options :
1590 session_options.media_description_options) {
1591 const ContentInfo* offer_content = &offer->contents()[msection_index];
1592 // Media types and MIDs must match between the remote offer and the
1593 // MediaDescriptionOptions.
1594 RTC_DCHECK(
1595 IsMediaContentOfType(offer_content, media_description_options.type));
1596 RTC_DCHECK(media_description_options.mid == offer_content->name);
1597 const ContentInfo* current_content = nullptr;
1598 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001599 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001600 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001601 }
zhihuang1c378ed2017-08-17 14:10:50 -07001602 switch (media_description_options.type) {
1603 case MEDIA_TYPE_AUDIO:
1604 if (!AddAudioContentForAnswer(
1605 media_description_options, session_options, offer_content,
1606 offer, current_content, current_description,
1607 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001608 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001609 return nullptr;
1610 }
1611 break;
1612 case MEDIA_TYPE_VIDEO:
1613 if (!AddVideoContentForAnswer(
1614 media_description_options, session_options, offer_content,
1615 offer, current_content, current_description,
1616 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001617 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001618 return nullptr;
1619 }
1620 break;
1621 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001622 if (!AddDataContentForAnswer(
1623 media_description_options, session_options, offer_content,
1624 offer, current_content, current_description,
1625 bundle_transport.get(), answer_data_codecs, &current_streams,
1626 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001627 return nullptr;
1628 }
1629 break;
1630 default:
1631 RTC_NOTREACHED();
1632 }
1633 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001634 // See if we can add the newly generated m= section to the BUNDLE group in
1635 // the answer.
1636 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001637 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001638 offer_bundle->HasContentName(added.name)) {
1639 answer_bundle.AddContentName(added.name);
1640 bundle_transport.reset(
1641 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643 }
1644
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001645 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1646 // it's empty. RFC5888 says:
1647 //
1648 // A SIP entity that receives an offer that contains an "a=group" line
1649 // with semantics that are understood MUST return an answer that
1650 // contains an "a=group" line with the same semantics.
1651 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001652 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001653 }
deadbeefb7892532017-02-22 19:35:18 -08001654
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001655 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001656 // Share the same ICE credentials and crypto params across all contents,
1657 // as BUNDLE requires.
1658 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001659 RTC_LOG(LS_ERROR)
1660 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001661 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001662 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001663
deadbeefb7892532017-02-22 19:35:18 -08001664 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001665 RTC_LOG(LS_ERROR)
1666 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001667 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668 }
1669 }
1670
Steve Antone831b8c2018-02-01 12:22:16 -08001671 // The following determines how to signal MSIDs to ensure compatibility with
1672 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001673 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001674 // Unified Plan needs to look at what the offer included to find the most
1675 // compatible answer.
1676 if (offer->msid_signaling() == 0) {
1677 // We end up here in one of three cases:
1678 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1679 // matter what we pick here.
1680 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1681 // it also doesn't matter what we pick here.
1682 // 3. Media that's either sendonly or inactive from the remote endpoint.
1683 // We don't have any information to say whether the endpoint is Plan B
1684 // or Unified Plan, so be conservative and send both.
1685 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1686 cricket::kMsidSignalingSsrcAttribute);
1687 } else if (offer->msid_signaling() ==
1688 (cricket::kMsidSignalingMediaSection |
1689 cricket::kMsidSignalingSsrcAttribute)) {
1690 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1691 // probably talking to a Unified Plan endpoint so respond with just
1692 // a=msid.
1693 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1694 } else {
1695 // Otherwise, it's clear which method the offerer is using so repeat that
1696 // back to them.
1697 answer->set_msid_signaling(offer->msid_signaling());
1698 }
1699 } else {
1700 // Plan B always signals MSID using a=ssrc lines.
1701 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1702 }
1703
Steve Anton6fe1fba2018-12-11 10:15:23 -08001704 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705}
1706
ossu075af922016-06-14 03:29:38 -07001707const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1708 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001709 switch (direction) {
1710 // If stream is inactive - generate list as if sendrecv.
1711 case RtpTransceiverDirection::kSendRecv:
1712 case RtpTransceiverDirection::kInactive:
1713 return audio_sendrecv_codecs_;
1714 case RtpTransceiverDirection::kSendOnly:
1715 return audio_send_codecs_;
1716 case RtpTransceiverDirection::kRecvOnly:
1717 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001718 }
Steve Anton1d03a752017-11-27 14:30:09 -08001719 RTC_NOTREACHED();
1720 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001721}
1722
1723const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1724 const RtpTransceiverDirection& offer,
1725 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001726 switch (answer) {
1727 // For inactive and sendrecv answers, generate lists as if we were to accept
1728 // the offer's direction. See RFC 3264 Section 6.1.
1729 case RtpTransceiverDirection::kSendRecv:
1730 case RtpTransceiverDirection::kInactive:
1731 return GetAudioCodecsForOffer(
1732 webrtc::RtpTransceiverDirectionReversed(offer));
1733 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001734 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001735 case RtpTransceiverDirection::kRecvOnly:
1736 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001737 }
Steve Anton1d03a752017-11-27 14:30:09 -08001738 RTC_NOTREACHED();
1739 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001740}
1741
Steve Anton5c72e712018-12-10 14:25:30 -08001742void MergeCodecsFromDescription(
1743 const std::vector<const ContentInfo*>& current_active_contents,
1744 AudioCodecs* audio_codecs,
1745 VideoCodecs* video_codecs,
1746 DataCodecs* data_codecs,
1747 UsedPayloadTypes* used_pltypes) {
1748 for (const ContentInfo* content : current_active_contents) {
1749 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001750 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001751 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001752 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001753 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001754 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001755 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001756 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001757 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001758 const DataContentDescription* data =
Steve Anton5c72e712018-12-10 14:25:30 -08001759 content->media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001760 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1761 }
1762 }
1763}
1764
1765// Getting codecs for an offer involves these steps:
1766//
1767// 1. Construct payload type -> codec mappings for current description.
1768// 2. Add any reference codecs that weren't already present
1769// 3. For each individual media description (m= section), filter codecs based
1770// on the directional attribute (happens in another method).
1771void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001772 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773 AudioCodecs* audio_codecs,
1774 VideoCodecs* video_codecs,
1775 DataCodecs* data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001776 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001777 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1778 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001779 UsedPayloadTypes used_pltypes;
1780 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1781 video_codecs, data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001782
Steve Anton5c72e712018-12-10 14:25:30 -08001783 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001784 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1785 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1786 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1787}
1788
1789// Getting codecs for an answer involves these steps:
1790//
1791// 1. Construct payload type -> codec mappings for current description.
1792// 2. Add any codecs from the offer that weren't already present.
1793// 3. Add any remaining codecs that weren't already present.
1794// 4. For each individual media description (m= section), filter codecs based
1795// on the directional attribute (happens in another method).
1796void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001797 const std::vector<const ContentInfo*>& current_active_contents,
1798 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001799 AudioCodecs* audio_codecs,
1800 VideoCodecs* video_codecs,
1801 DataCodecs* data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001802 // First - get all codecs from the current description if the media type
1803 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1804 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001805 UsedPayloadTypes used_pltypes;
1806 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1807 video_codecs, data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001808
1809 // Second - filter out codecs that we don't support at all and should ignore.
1810 AudioCodecs filtered_offered_audio_codecs;
1811 VideoCodecs filtered_offered_video_codecs;
1812 DataCodecs filtered_offered_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001813 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001814 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1815 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001816 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001817 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1818 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1819 filtered_offered_audio_codecs,
1820 offered_audio_codec, nullptr) &&
1821 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1822 offered_audio_codec, nullptr)) {
1823 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1824 }
1825 }
1826 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1827 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001828 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001829 for (const VideoCodec& offered_video_codec : video->codecs()) {
1830 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1831 filtered_offered_video_codecs,
1832 offered_video_codec, nullptr) &&
1833 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1834 offered_video_codec, nullptr)) {
1835 filtered_offered_video_codecs.push_back(offered_video_codec);
1836 }
1837 }
1838 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1839 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001840 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001841 for (const DataCodec& offered_data_codec : data->codecs()) {
1842 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1843 filtered_offered_data_codecs,
1844 offered_data_codec, nullptr) &&
1845 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1846 offered_data_codec, nullptr)) {
1847 filtered_offered_data_codecs.push_back(offered_data_codec);
1848 }
1849 }
1850 }
1851 }
1852
Steve Anton5c72e712018-12-10 14:25:30 -08001853 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001854 // |remote_offer|.
1855 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1856 &used_pltypes);
1857 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1858 &used_pltypes);
1859 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1860 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861}
1862
1863void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001864 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001865 RtpHeaderExtensions* offer_audio_extensions,
1866 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001867 // All header extensions allocated from the same range to avoid potential
1868 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001869 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001870 RtpHeaderExtensions all_regular_extensions;
1871 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001872
1873 // First - get all extensions from the current description if the media type
1874 // is used.
1875 // Add them to |used_ids| so the local ids are not reused if a new media
1876 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001877 for (const ContentInfo* content : current_active_contents) {
1878 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1879 const AudioContentDescription* audio =
1880 content->media_description()->as_audio();
1881 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1882 &all_regular_extensions, &all_encrypted_extensions,
1883 &used_ids);
1884 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1885 const VideoContentDescription* video =
1886 content->media_description()->as_video();
1887 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1888 &all_regular_extensions, &all_encrypted_extensions,
1889 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890 }
1891 }
1892
Steve Anton5c72e712018-12-10 14:25:30 -08001893 // Add our default RTP header extensions that are not in the current
1894 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001895 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1896 &all_regular_extensions, &all_encrypted_extensions,
1897 &used_ids);
1898 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1899 &all_regular_extensions, &all_encrypted_extensions,
1900 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001901
jbauch5869f502017-06-29 12:31:36 -07001902 // TODO(jbauch): Support adding encrypted header extensions to existing
1903 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001904 if (enable_encrypted_rtp_header_extensions_ &&
1905 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001906 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1907 &all_encrypted_extensions, &used_ids);
1908 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1909 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001910 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911}
1912
1913bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001914 const std::string& content_name,
1915 const TransportOptions& transport_options,
1916 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001917 SessionDescription* offer_desc,
1918 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001920 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001921 const TransportDescription* current_tdesc =
1922 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001923 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001924 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1925 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001926 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001927 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1928 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 }
Steve Anton06817cd2018-12-18 15:55:30 -08001930 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1931 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001932}
1933
Steve Anton1a9d3c32018-12-10 17:18:54 -08001934std::unique_ptr<TransportDescription>
1935MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936 const std::string& content_name,
1937 const SessionDescription* offer_desc,
1938 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001939 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001940 bool require_transport_attributes,
1941 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 if (!transport_desc_factory_)
1943 return NULL;
1944 const TransportDescription* offer_tdesc =
1945 GetTransportDescription(content_name, offer_desc);
1946 const TransportDescription* current_tdesc =
1947 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001948 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1949 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001950 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951}
1952
1953bool MediaSessionDescriptionFactory::AddTransportAnswer(
1954 const std::string& content_name,
1955 const TransportDescription& transport_desc,
1956 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001957 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001958 return true;
1959}
1960
zhihuang1c378ed2017-08-17 14:10:50 -07001961// |audio_codecs| = set of all possible codecs that can be used, with correct
1962// payload type mappings
1963//
1964// |supported_audio_codecs| = set of codecs that are supported for the direction
1965// of this m= section
1966//
1967// acd->codecs() = set of previously negotiated codecs for this m= section
1968//
1969// The payload types should come from audio_codecs, but the order should come
1970// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1971// change existing codec priority, and that new codecs are added with the right
1972// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001973bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001974 const MediaDescriptionOptions& media_description_options,
1975 const MediaSessionOptions& session_options,
1976 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001977 const SessionDescription* current_description,
1978 const RtpHeaderExtensions& audio_rtp_extensions,
1979 const AudioCodecs& audio_codecs,
1980 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001981 SessionDescription* desc,
1982 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001983 // Filter audio_codecs (which includes all codecs, with correctly remapped
1984 // payload types) based on transceiver direction.
1985 const AudioCodecs& supported_audio_codecs =
1986 GetAudioCodecsForOffer(media_description_options.direction);
1987
1988 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001989 // Add the codecs from current content if it exists and is not rejected nor
1990 // recycled.
1991 if (current_content && !current_content->rejected &&
1992 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001993 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001994 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001995 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001996 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001997 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1998 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001999 filtered_codecs.push_back(codec);
2000 }
2001 }
2002 }
2003 // Add other supported audio codecs.
2004 AudioCodec found_codec;
2005 for (const AudioCodec& codec : supported_audio_codecs) {
2006 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2007 codec, &found_codec) &&
2008 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2009 codec, nullptr)) {
2010 // Use the |found_codec| from |audio_codecs| because it has the correctly
2011 // mapped payload type.
2012 filtered_codecs.push_back(found_codec);
2013 }
2014 }
deadbeef44f08192015-12-15 16:20:09 -08002015
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002016 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002017 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2018 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002019
kwiberg31022942016-03-11 14:18:21 -08002020 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002021 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002022 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2023 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002024 if (!CreateMediaContentOffer(media_description_options, session_options,
2025 filtered_codecs, sdes_policy,
2026 GetCryptos(current_content), crypto_suites,
2027 audio_rtp_extensions, ssrc_generator_,
2028 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002029 return false;
2030 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002031
2032 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2033 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002034
Steve Anton4e70a722017-11-28 14:57:10 -08002035 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002036
Steve Anton5adfafd2017-12-20 16:34:00 -08002037 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002038 media_description_options.stopped, audio.release());
2039 if (!AddTransportOffer(media_description_options.mid,
2040 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002041 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 return false;
2043 }
2044
2045 return true;
2046}
2047
2048bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002049 const MediaDescriptionOptions& media_description_options,
2050 const MediaSessionOptions& session_options,
2051 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052 const SessionDescription* current_description,
2053 const RtpHeaderExtensions& video_rtp_extensions,
2054 const VideoCodecs& video_codecs,
2055 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002056 SessionDescription* desc,
2057 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002058 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002059 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2060 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002061
kwiberg31022942016-03-11 14:18:21 -08002062 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002063 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002064 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2065 &crypto_suites);
2066
2067 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002068 // Add the codecs from current content if it exists and is not rejected nor
2069 // recycled.
2070 if (current_content && !current_content->rejected &&
2071 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002072 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002073 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002074 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002075 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002076 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002077 nullptr)) {
2078 filtered_codecs.push_back(codec);
2079 }
2080 }
2081 }
2082 // Add other supported video codecs.
2083 VideoCodec found_codec;
2084 for (const VideoCodec& codec : video_codecs_) {
2085 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2086 &found_codec) &&
2087 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2088 nullptr)) {
2089 // Use the |found_codec| from |video_codecs| because it has the correctly
2090 // mapped payload type.
2091 filtered_codecs.push_back(found_codec);
2092 }
2093 }
2094
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002095 if (!CreateMediaContentOffer(media_description_options, session_options,
2096 filtered_codecs, sdes_policy,
2097 GetCryptos(current_content), crypto_suites,
2098 video_rtp_extensions, ssrc_generator_,
2099 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002100 return false;
2101 }
2102
zhihuang1c378ed2017-08-17 14:10:50 -07002103 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002104
2105 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2106 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002107
Steve Anton4e70a722017-11-28 14:57:10 -08002108 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002109
Steve Anton5adfafd2017-12-20 16:34:00 -08002110 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002111 media_description_options.stopped, video.release());
2112 if (!AddTransportOffer(media_description_options.mid,
2113 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002114 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002115 return false;
2116 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002117 return true;
2118}
2119
2120bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002121 const MediaDescriptionOptions& media_description_options,
2122 const MediaSessionOptions& session_options,
2123 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002124 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07002125 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002126 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002127 SessionDescription* desc,
2128 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002129 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2130
kwiberg31022942016-03-11 14:18:21 -08002131 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07002132 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2133 // If the DataChannel type is not specified, use the DataChannel type in
2134 // the current description.
2135 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002136 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002137 is_sctp = (current_content->media_description()->protocol() ==
2138 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002139 }
deadbeef44f08192015-12-15 16:20:09 -08002140
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002141 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002142 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2143 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002144 std::vector<std::string> crypto_suites;
2145 if (is_sctp) {
2146 // SDES doesn't make sense for SCTP, so we disable it, and we only
2147 // get SDES crypto suites for RTP-based data channels.
2148 sdes_policy = cricket::SEC_DISABLED;
2149 // Unlike SetMediaProtocol below, we need to set the protocol
2150 // before we call CreateMediaContentOffer. Otherwise,
2151 // CreateMediaContentOffer won't know this is SCTP and will
2152 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002153 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2154 // it's safe to do so. Older versions of webrtc would reject these
2155 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002156 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2157 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002158 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002159 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002160 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002161 }
2162
zhihuang1c378ed2017-08-17 14:10:50 -07002163 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002164 if (!CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002165 media_description_options, session_options, data_codecs, sdes_policy,
2166 GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002167 ssrc_generator_, current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002168 return false;
2169 }
2170
2171 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002172 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002173 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002174 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002175 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002176 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002177 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002178 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002179 }
zhihuang1c378ed2017-08-17 14:10:50 -07002180 if (!AddTransportOffer(media_description_options.mid,
2181 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002182 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002183 return false;
2184 }
2185 return true;
2186}
2187
zhihuang1c378ed2017-08-17 14:10:50 -07002188// |audio_codecs| = set of all possible codecs that can be used, with correct
2189// payload type mappings
2190//
2191// |supported_audio_codecs| = set of codecs that are supported for the direction
2192// of this m= section
2193//
2194// acd->codecs() = set of previously negotiated codecs for this m= section
2195//
2196// The payload types should come from audio_codecs, but the order should come
2197// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2198// change existing codec priority, and that new codecs are added with the right
2199// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002200bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002201 const MediaDescriptionOptions& media_description_options,
2202 const MediaSessionOptions& session_options,
2203 const ContentInfo* offer_content,
2204 const SessionDescription* offer_description,
2205 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002206 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002207 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002208 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002209 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002210 SessionDescription* answer,
2211 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002212 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002213 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002214 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002215
Steve Anton1a9d3c32018-12-10 17:18:54 -08002216 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002217 media_description_options.mid, offer_description,
2218 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002219 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002220 if (!audio_transport) {
2221 return false;
2222 }
2223
zhihuang1c378ed2017-08-17 14:10:50 -07002224 // Pick codecs based on the requested communications direction in the offer
2225 // and the selected direction in the answer.
2226 // Note these will be filtered one final time in CreateMediaContentAnswer.
2227 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002228 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002229 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002230 AudioCodecs supported_audio_codecs =
2231 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2232
2233 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002234 // Add the codecs from current content if it exists and is not rejected nor
2235 // recycled.
2236 if (current_content && !current_content->rejected &&
2237 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002238 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002239 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002240 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002241 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002242 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2243 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002244 filtered_codecs.push_back(codec);
2245 }
2246 }
2247 }
2248 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002249 for (const AudioCodec& codec : supported_audio_codecs) {
2250 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002251 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002252 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2253 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002254 // We should use the local codec with local parameters and the codec id
2255 // would be correctly mapped in |NegotiateCodecs|.
2256 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002257 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002258 }
2259
zhihuang1c378ed2017-08-17 14:10:50 -07002260 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2261 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002262 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002263 new AudioContentDescription());
2264 // Do not require or create SDES cryptos if DTLS is used.
2265 cricket::SecurePolicy sdes_policy =
2266 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2267 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002268 offer_audio_description, media_description_options, session_options,
2269 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002270 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002271 enable_encrypted_rtp_header_extensions_, current_streams,
2272 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 return false; // Fails the session setup.
2274 }
2275
deadbeefb7892532017-02-22 19:35:18 -08002276 bool secure = bundle_transport ? bundle_transport->description.secure()
2277 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002278 bool rejected = media_description_options.stopped ||
2279 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002280 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2281 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002282 if (!AddTransportAnswer(media_description_options.mid,
2283 *(audio_transport.get()), answer)) {
2284 return false;
2285 }
2286
2287 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002288 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2289 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002290 }
2291
zhihuang1c378ed2017-08-17 14:10:50 -07002292 answer->AddContent(media_description_options.mid, offer_content->type,
2293 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002294 return true;
2295}
2296
2297bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002298 const MediaDescriptionOptions& media_description_options,
2299 const MediaSessionOptions& session_options,
2300 const ContentInfo* offer_content,
2301 const SessionDescription* offer_description,
2302 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002303 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002304 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002305 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002307 SessionDescription* answer,
2308 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002309 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002310 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002311 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002312
Steve Anton1a9d3c32018-12-10 17:18:54 -08002313 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002314 media_description_options.mid, offer_description,
2315 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002316 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002317 if (!video_transport) {
2318 return false;
2319 }
2320
zhihuang1c378ed2017-08-17 14:10:50 -07002321 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002322 // Add the codecs from current content if it exists and is not rejected nor
2323 // recycled.
2324 if (current_content && !current_content->rejected &&
2325 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002326 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002327 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002328 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002329 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002330 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002331 nullptr)) {
2332 filtered_codecs.push_back(codec);
2333 }
2334 }
2335 }
2336 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002337 for (const VideoCodec& codec : video_codecs_) {
2338 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002339 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002340 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2341 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002342 // We should use the local codec with local parameters and the codec id
2343 // would be correctly mapped in |NegotiateCodecs|.
2344 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002345 }
2346 }
2347
2348 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2349 session_options.bundle_enabled;
2350
kwiberg31022942016-03-11 14:18:21 -08002351 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002352 new VideoContentDescription());
2353 // Do not require or create SDES cryptos if DTLS is used.
2354 cricket::SecurePolicy sdes_policy =
2355 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002356 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002357 offer_video_description, media_description_options, session_options,
2358 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002359 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002360 enable_encrypted_rtp_header_extensions_, current_streams,
2361 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002362 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002363 }
deadbeefb7892532017-02-22 19:35:18 -08002364 bool secure = bundle_transport ? bundle_transport->description.secure()
2365 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002366 bool rejected = media_description_options.stopped ||
2367 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002368 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2369 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002370 if (!AddTransportAnswer(media_description_options.mid,
2371 *(video_transport.get()), answer)) {
2372 return false;
2373 }
2374
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002375 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002376 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002377 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002378 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2379 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002380 }
zhihuang1c378ed2017-08-17 14:10:50 -07002381 answer->AddContent(media_description_options.mid, offer_content->type,
2382 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002383 return true;
2384}
2385
2386bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002387 const MediaDescriptionOptions& media_description_options,
2388 const MediaSessionOptions& session_options,
2389 const ContentInfo* offer_content,
2390 const SessionDescription* offer_description,
2391 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002392 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002393 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002394 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002395 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002396 SessionDescription* answer,
2397 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002398 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002399 media_description_options.mid, offer_description,
2400 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002401 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002402 if (!data_transport) {
2403 return false;
2404 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002405
kwiberg31022942016-03-11 14:18:21 -08002406 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002407 new DataContentDescription());
2408 // Do not require or create SDES cryptos if DTLS is used.
2409 cricket::SecurePolicy sdes_policy =
2410 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002411 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2412 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002413 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2414 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002415 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002416 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002417 offer_data_description, media_description_options, session_options,
2418 data_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002419 RtpHeaderExtensions(), ssrc_generator_,
2420 enable_encrypted_rtp_header_extensions_, current_streams,
2421 bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002422 return false; // Fails the session setup.
2423 }
2424
zstein4b2e0822017-02-17 19:48:38 -08002425 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002426 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2427 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2428
deadbeefb7892532017-02-22 19:35:18 -08002429 bool secure = bundle_transport ? bundle_transport->description.secure()
2430 : data_transport->secure();
2431
zhihuang1c378ed2017-08-17 14:10:50 -07002432 bool rejected = session_options.data_channel_type == DCT_NONE ||
2433 media_description_options.stopped ||
2434 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002435 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2436 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002437 if (!AddTransportAnswer(media_description_options.mid,
2438 *(data_transport.get()), answer)) {
2439 return false;
2440 }
2441
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002442 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002443 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002444 } else {
2445 // RFC 3264
2446 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002447 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002448 }
zhihuang1c378ed2017-08-17 14:10:50 -07002449 answer->AddContent(media_description_options.mid, offer_content->type,
2450 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002451 return true;
2452}
2453
zhihuang1c378ed2017-08-17 14:10:50 -07002454void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2455 audio_sendrecv_codecs_.clear();
2456 all_audio_codecs_.clear();
2457 // Compute the audio codecs union.
2458 for (const AudioCodec& send : audio_send_codecs_) {
2459 all_audio_codecs_.push_back(send);
2460 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2461 send, nullptr)) {
2462 // It doesn't make sense to have an RTX codec we support sending but not
2463 // receiving.
2464 RTC_DCHECK(!IsRtxCodec(send));
2465 }
2466 }
2467 for (const AudioCodec& recv : audio_recv_codecs_) {
2468 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2469 recv, nullptr)) {
2470 all_audio_codecs_.push_back(recv);
2471 }
2472 }
2473 // Use NegotiateCodecs to merge our codec lists, since the operation is
2474 // essentially the same. Put send_codecs as the offered_codecs, which is the
2475 // order we'd like to follow. The reasoning is that encoding is usually more
2476 // expensive than decoding, and prioritizing a codec in the send list probably
2477 // means it's a codec we can handle efficiently.
2478 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2479 &audio_sendrecv_codecs_);
2480}
2481
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002483 return (content && (content->type == MediaProtocolType::kRtp ||
2484 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002485}
2486
2487bool IsAudioContent(const ContentInfo* content) {
2488 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2489}
2490
2491bool IsVideoContent(const ContentInfo* content) {
2492 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2493}
2494
2495bool IsDataContent(const ContentInfo* content) {
2496 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2497}
2498
deadbeef0ed85b22016-02-23 17:24:52 -08002499const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2500 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002501 for (const ContentInfo& content : contents) {
2502 if (IsMediaContentOfType(&content, media_type)) {
2503 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504 }
2505 }
deadbeef0ed85b22016-02-23 17:24:52 -08002506 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002507}
2508
2509const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2510 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2511}
2512
2513const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2514 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2515}
2516
2517const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2518 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2519}
2520
Steve Antonad7bffc2018-01-22 10:21:56 -08002521const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2522 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002523 if (sdesc == nullptr) {
2524 return nullptr;
2525 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526
2527 return GetFirstMediaContent(sdesc->contents(), media_type);
2528}
2529
2530const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2531 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2532}
2533
2534const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2535 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2536}
2537
2538const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2539 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2540}
2541
2542const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002543 const SessionDescription* sdesc,
2544 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002546 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002547}
2548
2549const AudioContentDescription* GetFirstAudioContentDescription(
2550 const SessionDescription* sdesc) {
2551 return static_cast<const AudioContentDescription*>(
2552 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2553}
2554
2555const VideoContentDescription* GetFirstVideoContentDescription(
2556 const SessionDescription* sdesc) {
2557 return static_cast<const VideoContentDescription*>(
2558 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2559}
2560
2561const DataContentDescription* GetFirstDataContentDescription(
2562 const SessionDescription* sdesc) {
2563 return static_cast<const DataContentDescription*>(
2564 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2565}
2566
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002567//
2568// Non-const versions of the above functions.
2569//
2570
Steve Anton36b29d12017-10-30 09:57:42 -07002571ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002572 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002573 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002574 if (IsMediaContentOfType(&content, media_type)) {
2575 return &content;
2576 }
2577 }
2578 return nullptr;
2579}
2580
Steve Anton36b29d12017-10-30 09:57:42 -07002581ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002582 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2583}
2584
Steve Anton36b29d12017-10-30 09:57:42 -07002585ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002586 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2587}
2588
Steve Anton36b29d12017-10-30 09:57:42 -07002589ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002590 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2591}
2592
Steve Antonad7bffc2018-01-22 10:21:56 -08002593ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2594 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002595 if (sdesc == nullptr) {
2596 return nullptr;
2597 }
2598
Steve Anton36b29d12017-10-30 09:57:42 -07002599 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002600}
2601
2602ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2603 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2604}
2605
2606ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2607 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2608}
2609
2610ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2611 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2612}
2613
2614MediaContentDescription* GetFirstMediaContentDescription(
2615 SessionDescription* sdesc,
2616 MediaType media_type) {
2617 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002618 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002619}
2620
2621AudioContentDescription* GetFirstAudioContentDescription(
2622 SessionDescription* sdesc) {
2623 return static_cast<AudioContentDescription*>(
2624 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2625}
2626
2627VideoContentDescription* GetFirstVideoContentDescription(
2628 SessionDescription* sdesc) {
2629 return static_cast<VideoContentDescription*>(
2630 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2631}
2632
2633DataContentDescription* GetFirstDataContentDescription(
2634 SessionDescription* sdesc) {
2635 return static_cast<DataContentDescription*>(
2636 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2637}
2638
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639} // namespace cricket