blob: e840b33fc1a6af70d39d1f76afddab8c462ea97c [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
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800475 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800476 SimulcastDescription simulcast;
477 simulcast.send_layers() =
478 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800479 description->set_simulcast_description(simulcast);
480}
481
zhihuang1c378ed2017-08-17 14:10:50 -0700482// Adds a StreamParams for each SenderOptions in |sender_options| to
483// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484// |current_params| - All currently known StreamParams of any media type.
485template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700486static bool AddStreamParams(
487 const std::vector<SenderOptions>& sender_options,
488 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800489 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700490 StreamParamsVec* current_streams,
491 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700492 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700493 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700494 return true;
495 }
496
Noah Richards2e7a0982015-05-18 14:02:54 -0700497 const bool include_rtx_streams =
498 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499
brandtr03d5fb12016-11-22 03:37:59 -0800500 const bool include_flexfec_stream =
501 ContainsFlexfecCodec(content_description->codecs());
502
zhihuang1c378ed2017-08-17 14:10:50 -0700503 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 // groupid is empty for StreamParams generated using
505 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700506 StreamParams* param =
507 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000508 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700509 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800510 StreamParams stream_param =
511 sender.rids.empty()
512 ?
513 // Signal SSRCs and legacy simulcast (if requested).
514 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800515 sender, rtcp_cname, include_rtx_streams,
516 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800517 :
518 // Signal RIDs and spec-compliant simulcast (if requested).
519 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
520
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 content_description->AddStream(stream_param);
522
523 // Store the new StreamParams in current_streams.
524 // This is necessary so that we can use the CNAME for other media types.
525 current_streams->push_back(stream_param);
526 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700527 // Use existing generated SSRCs/groups, but update the sync_label if
528 // necessary. This may be needed if a MediaStreamTrack was moved from one
529 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800530 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000531 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 }
533 }
534 return true;
535}
536
537// Updates the transport infos of the |sdesc| according to the given
538// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800539// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
540// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
542 SessionDescription* sdesc) {
543 // The bundle should not be empty.
544 if (!sdesc || !bundle_group.FirstContentName()) {
545 return false;
546 }
547
548 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700549 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 const TransportInfo* selected_transport_info =
551 sdesc->GetTransportInfoByName(selected_content_name);
552 if (!selected_transport_info) {
553 return false;
554 }
555
556 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700557 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700559 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800561 ConnectionRole selected_connection_role =
562 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700563 for (TransportInfo& transport_info : sdesc->transport_infos()) {
564 if (bundle_group.HasContentName(transport_info.content_name) &&
565 transport_info.content_name != selected_content_name) {
566 transport_info.description.ice_ufrag = selected_ufrag;
567 transport_info.description.ice_pwd = selected_pwd;
568 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 }
570 }
571 return true;
572}
573
574// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
575// sets it to |cryptos|.
576static bool GetCryptosByName(const SessionDescription* sdesc,
577 const std::string& content_name,
578 CryptoParamsVec* cryptos) {
579 if (!sdesc || !cryptos) {
580 return false;
581 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800583 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 return false;
585 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800586 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 return true;
588}
589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
591// which are not available in |filter|.
592static void PruneCryptos(const CryptoParamsVec& filter,
593 CryptoParamsVec* target_cryptos) {
594 if (!target_cryptos) {
595 return;
596 }
tzik21995802018-04-26 17:38:28 +0900597
598 target_cryptos->erase(
599 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
600 // Returns true if the |crypto|'s cipher_suite is not
601 // found in |filter|.
602 [&filter](const CryptoParams& crypto) {
603 for (const CryptoParams& entry : filter) {
604 if (entry.cipher_suite == crypto.cipher_suite)
605 return false;
606 }
607 return true;
608 }),
609 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610}
611
Steve Antonfa2260d2017-12-28 16:38:23 -0800612bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800613 return protocol.empty() ||
614 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
615}
616
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617static bool IsRtpContent(SessionDescription* sdesc,
618 const std::string& content_name) {
619 bool is_rtp = false;
620 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800621 if (content && content->media_description()) {
622 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 }
624 return is_rtp;
625}
626
627// Updates the crypto parameters of the |sdesc| according to the given
628// |bundle_group|. The crypto parameters of all the contents within the
629// |bundle_group| should be updated to use the common subset of the
630// available cryptos.
631static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
632 SessionDescription* sdesc) {
633 // The bundle should not be empty.
634 if (!sdesc || !bundle_group.FirstContentName()) {
635 return false;
636 }
637
wu@webrtc.org78187522013-10-07 23:32:02 +0000638 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 // Get the common cryptos.
640 const ContentNames& content_names = bundle_group.content_names();
641 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700642 bool first = true;
643 for (const std::string& content_name : content_names) {
644 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 continue;
646 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000647 // The common cryptos are needed if any of the content does not have DTLS
648 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700649 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000650 common_cryptos_needed = true;
651 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700652 if (first) {
653 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700655 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 return false;
657 }
658 if (common_cryptos.empty()) {
659 // If there's no crypto params, we should just return.
660 return true;
661 }
662 } else {
663 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700664 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 return false;
666 }
667 PruneCryptos(cryptos, &common_cryptos);
668 }
669 }
670
wu@webrtc.org78187522013-10-07 23:32:02 +0000671 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 return false;
673 }
674
675 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700676 for (const std::string& content_name : content_names) {
677 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 continue;
679 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700680 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800682 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 if (!media_desc) {
684 return false;
685 }
686 media_desc->set_cryptos(common_cryptos);
687 }
688 }
689 return true;
690}
691
Steve Anton5c72e712018-12-10 14:25:30 -0800692static std::vector<const ContentInfo*> GetActiveContents(
693 const SessionDescription& description,
694 const MediaSessionOptions& session_options) {
695 std::vector<const ContentInfo*> active_contents;
696 for (size_t i = 0; i < description.contents().size(); ++i) {
697 RTC_DCHECK_LT(i, session_options.media_description_options.size());
698 const ContentInfo& content = description.contents()[i];
699 const MediaDescriptionOptions& media_options =
700 session_options.media_description_options[i];
701 if (!content.rejected && !media_options.stopped &&
702 content.name == media_options.mid) {
703 active_contents.push_back(&content);
704 }
705 }
706 return active_contents;
707}
708
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709template <class C>
710static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800711 for (const auto& codec : codecs) {
712 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713 return true;
714 }
715 }
716 return false;
717}
718
719template <class C>
720static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200721 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722}
723
brandtr03d5fb12016-11-22 03:37:59 -0800724template <class C>
725static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
726 for (const auto& codec : codecs) {
727 if (IsFlexfecCodec(codec)) {
728 return true;
729 }
730 }
731 return false;
732}
733
734template <class C>
735static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200736 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800737}
738
zhihuang1c378ed2017-08-17 14:10:50 -0700739// Create a media content to be offered for the given |sender_options|,
740// according to the given options.rtcp_mux, session_options.is_muc, codecs,
741// secure_transport, crypto, and current_streams. If we don't currently have
742// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
743// created (according to crypto_suites). The created content is added to the
744// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745template <class C>
746static bool CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800747 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700748 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000750 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751 const CryptoParamsVec* current_cryptos,
752 const std::vector<std::string>& crypto_suites,
753 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800754 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755 StreamParamsVec* current_streams,
756 MediaContentDescriptionImpl<C>* offer) {
757 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758
zhihuang1c378ed2017-08-17 14:10:50 -0700759 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700760 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
761 offer->set_rtcp_reduced_size(true);
762 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 offer->set_rtp_header_extensions(rtp_extensions);
764
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800765 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800766 session_options.rtcp_cname, ssrc_generator,
767 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 return false;
769 }
770
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800771 AddSimulcastToMediaDescription(media_description_options, offer);
772
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 if (secure_policy != SEC_DISABLED) {
774 if (current_cryptos) {
775 AddMediaCryptos(*current_cryptos, offer);
776 }
777 if (offer->cryptos().empty()) {
778 if (!CreateMediaCryptos(crypto_suites, offer)) {
779 return false;
780 }
781 }
782 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783
deadbeef7af91dd2016-12-13 11:29:11 -0800784 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 return false;
786 }
787 return true;
788}
789
790template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000791static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800792 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000793 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800794 const int codec2_id) {
795 const C* codec1 = FindCodecById(codecs1, codec1_id);
796 const C* codec2 = FindCodecById(codecs2, codec2_id);
797 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000798}
799
800template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801static void NegotiateCodecs(const std::vector<C>& local_codecs,
802 const std::vector<C>& offered_codecs,
803 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800804 for (const C& ours : local_codecs) {
805 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700806 // Note that we intentionally only find one matching codec for each of our
807 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800808 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
809 C negotiated = ours;
810 negotiated.IntersectFeedbackParams(theirs);
811 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800812 const auto apt_it =
813 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800814 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800815 RTC_DCHECK(apt_it != theirs.params.end());
816 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 }
Niels Möller039743e2018-10-23 10:07:25 +0200818 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800819 webrtc::H264::GenerateProfileLevelIdForAnswer(
820 ours.params, theirs.params, &negotiated.params);
821 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800822 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700823 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800824 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 }
826 }
deadbeef67cf2c12016-04-13 10:07:16 -0700827 // RFC3264: Although the answerer MAY list the formats in their desired
828 // order of preference, it is RECOMMENDED that unless there is a
829 // specific reason, the answerer list formats in the same relative order
830 // they were present in the offer.
831 std::unordered_map<int, int> payload_type_preferences;
832 int preference = static_cast<int>(offered_codecs.size() + 1);
833 for (const C& codec : offered_codecs) {
834 payload_type_preferences[codec.id] = preference--;
835 }
836 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
837 [&payload_type_preferences](const C& a, const C& b) {
838 return payload_type_preferences[a.id] >
839 payload_type_preferences[b.id];
840 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841}
842
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800843// Finds a codec in |codecs2| that matches |codec_to_match|, which is
844// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
845// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800847static bool FindMatchingCodec(const std::vector<C>& codecs1,
848 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 const C& codec_to_match,
850 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700851 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
852 // codecs' associated codecs correctly. If not, that's a programming error.
853 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
854 [&codec_to_match](const C& codec) {
855 return &codec == &codec_to_match;
856 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800857 for (const C& potential_match : codecs2) {
858 if (potential_match.Matches(codec_to_match)) {
859 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800860 int apt_value_1 = 0;
861 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800862 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
863 &apt_value_1) ||
864 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
865 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100866 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800867 continue;
868 }
869 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
870 apt_value_2)) {
871 continue;
872 }
873 }
874 if (found_codec) {
875 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 }
877 return true;
878 }
879 }
880 return false;
881}
882
zhihuang1c378ed2017-08-17 14:10:50 -0700883// Find the codec in |codec_list| that |rtx_codec| is associated with.
884template <class C>
885static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
886 const C& rtx_codec) {
887 std::string associated_pt_str;
888 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
889 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100890 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
891 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700892 return nullptr;
893 }
894
895 int associated_pt;
896 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100897 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
898 << " of RTX codec " << rtx_codec.name
899 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700900 return nullptr;
901 }
902
903 // Find the associated reference codec for the reference RTX codec.
904 const C* associated_codec = FindCodecById(codec_list, associated_pt);
905 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100906 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
907 << associated_pt << " for RTX codec " << rtx_codec.name
908 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700909 }
910 return associated_codec;
911}
912
913// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914// already exist in |offered_codecs| and ensure the payload types don't
915// collide.
916template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700917static void MergeCodecs(const std::vector<C>& reference_codecs,
918 std::vector<C>* offered_codecs,
919 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800921 for (const C& reference_codec : reference_codecs) {
922 if (!IsRtxCodec(reference_codec) &&
923 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
924 reference_codec, nullptr)) {
925 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000926 used_pltypes->FindAndSetIdUsed(&codec);
927 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000928 }
929 }
930
931 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800932 for (const C& reference_codec : reference_codecs) {
933 if (IsRtxCodec(reference_codec) &&
934 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
935 reference_codec, nullptr)) {
936 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700937 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700938 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700939 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700940 continue;
941 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800942 // Find a codec in the offered list that matches the reference codec.
943 // Its payload type may be different than the reference codec.
944 C matching_codec;
945 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800946 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100947 RTC_LOG(LS_WARNING)
948 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800949 continue;
950 }
951
952 rtx_codec.params[kCodecParamAssociatedPayloadType] =
953 rtc::ToString(matching_codec.id);
954 used_pltypes->FindAndSetIdUsed(&rtx_codec);
955 offered_codecs->push_back(rtx_codec);
956 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957 }
958}
959
zhihuang1c378ed2017-08-17 14:10:50 -0700960static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
961 const webrtc::RtpExtension& ext_to_match,
962 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700963 auto it =
964 std::find_if(extensions.begin(), extensions.end(),
965 [&ext_to_match](const webrtc::RtpExtension& extension) {
966 // We assume that all URIs are given in a canonical
967 // format.
968 return extension.uri == ext_to_match.uri &&
969 extension.encrypt == ext_to_match.encrypt;
970 });
971 if (it == extensions.end()) {
972 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700973 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700974 if (found_extension) {
975 *found_extension = *it;
976 }
977 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700978}
979
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700981 const webrtc::RtpExtension& ext_to_match,
982 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700983 // We assume that all URIs are given in a canonical format.
984 const webrtc::RtpExtension* found =
985 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
986 ext_to_match.uri);
987 if (!found) {
988 return false;
989 }
990 if (found_extension) {
991 *found_extension = *found;
992 }
993 return true;
994}
995
996static bool FindByUriWithEncryptionPreference(
997 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200998 const webrtc::RtpExtension& ext_to_match,
999 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001000 webrtc::RtpExtension* found_extension) {
1001 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001002 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001004 if (extension.uri == ext_to_match.uri) {
1005 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001006 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001007 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001008 }
1009 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001011 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 }
1013 }
jbauch5869f502017-06-29 12:31:36 -07001014 if (unencrypted_extension) {
1015 if (found_extension) {
1016 *found_extension = *unencrypted_extension;
1017 }
1018 return true;
1019 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 return false;
1021}
1022
zhihuang1c378ed2017-08-17 14:10:50 -07001023// Adds all extensions from |reference_extensions| to |offered_extensions| that
1024// don't already exist in |offered_extensions| and ensure the IDs don't
1025// collide. If an extension is added, it's also added to |regular_extensions| or
1026// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1027// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1028// |offered_extensions| is for either audio or video while |regular_extensions|
1029// and |encrypted_extensions| are used for both audio and video. There could be
1030// overlap between audio extensions and video extensions.
1031static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1032 RtpHeaderExtensions* offered_extensions,
1033 RtpHeaderExtensions* regular_extensions,
1034 RtpHeaderExtensions* encrypted_extensions,
1035 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001036 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001037 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1038 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001039 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001040 if (reference_extension.encrypt) {
1041 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1042 &existing)) {
1043 offered_extensions->push_back(existing);
1044 } else {
1045 used_ids->FindAndSetIdUsed(&reference_extension);
1046 encrypted_extensions->push_back(reference_extension);
1047 offered_extensions->push_back(reference_extension);
1048 }
olka3c747662017-08-17 06:50:32 -07001049 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001050 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1051 &existing)) {
1052 offered_extensions->push_back(existing);
1053 } else {
1054 used_ids->FindAndSetIdUsed(&reference_extension);
1055 regular_extensions->push_back(reference_extension);
1056 offered_extensions->push_back(reference_extension);
1057 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001058 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059 }
1060 }
1061}
1062
jbauch5869f502017-06-29 12:31:36 -07001063static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1064 RtpHeaderExtensions* all_extensions,
1065 UsedRtpHeaderExtensionIds* used_ids) {
1066 RtpHeaderExtensions encrypted_extensions;
1067 for (const webrtc::RtpExtension& extension : *extensions) {
1068 webrtc::RtpExtension existing;
1069 // Don't add encrypted extensions again that were already included in a
1070 // previous offer or regular extensions that are also included as encrypted
1071 // extensions.
1072 if (extension.encrypt ||
1073 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1074 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001075 &existing) &&
1076 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001077 continue;
1078 }
1079
1080 if (FindByUri(*all_extensions, extension, &existing)) {
1081 encrypted_extensions.push_back(existing);
1082 } else {
1083 webrtc::RtpExtension encrypted(extension);
1084 encrypted.encrypt = true;
1085 used_ids->FindAndSetIdUsed(&encrypted);
1086 all_extensions->push_back(encrypted);
1087 encrypted_extensions.push_back(encrypted);
1088 }
1089 }
1090 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001091 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001092}
1093
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094static void NegotiateRtpHeaderExtensions(
1095 const RtpHeaderExtensions& local_extensions,
1096 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001097 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001099 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001100 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001101 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001102 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001103 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104 // We respond with their RTP header extension id.
1105 negotiated_extenstions->push_back(theirs);
1106 }
1107 }
1108}
1109
1110static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001111 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1112 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001113 return absl::EqualsIgnoreCase(
1114 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001115 }),
1116 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001117}
1118
zhihuang1c378ed2017-08-17 14:10:50 -07001119// Create a media content to be answered for the given |sender_options|
1120// according to the given session_options.rtcp_mux, session_options.streams,
1121// codecs, crypto, and current_streams. If we don't currently have crypto (in
1122// current_cryptos) and it is enabled (in secure_policy), crypto is created
1123// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1124// negotiated with the offer. If the negotiation fails, this method returns
1125// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126template <class C>
1127static bool CreateMediaContentAnswer(
1128 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001129 const MediaDescriptionOptions& media_description_options,
1130 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001132 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001133 const CryptoParamsVec* current_cryptos,
1134 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001135 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001136 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 bool bundle_enabled,
1139 MediaContentDescriptionImpl<C>* answer) {
1140 std::vector<C> negotiated_codecs;
1141 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1142 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001144
Johannes Kron9581bc42018-10-23 10:17:39 +02001145 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001146 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001147 NegotiateRtpHeaderExtensions(
1148 local_rtp_extenstions, offer->rtp_header_extensions(),
1149 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1151
zhihuang1c378ed2017-08-17 14:10:50 -07001152 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001153 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1154 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1155 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156
1157 if (sdes_policy != SEC_DISABLED) {
1158 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001159 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1160 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001161 if (current_cryptos) {
1162 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1163 }
1164 answer->AddCrypto(crypto);
1165 }
1166 }
1167
deadbeef7af91dd2016-12-13 11:29:11 -08001168 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 return false;
1170 }
1171
zhihuang1c378ed2017-08-17 14:10:50 -07001172 if (!AddStreamParams(media_description_options.sender_options,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001173 session_options.rtcp_cname, ssrc_generator,
1174 current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 return false; // Something went seriously wrong.
1176 }
1177
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001178 AddSimulcastToMediaDescription(media_description_options, answer);
1179
Steve Anton4e70a722017-11-28 14:57:10 -08001180 answer->set_direction(NegotiateRtpTransceiverDirection(
1181 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182 return true;
1183}
1184
1185static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001186 const std::string& protocol,
1187 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001188 // Since not all applications serialize and deserialize the media protocol,
1189 // we will have to accept |protocol| to be empty.
1190 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 return true;
1192 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001193
zhihuangcf5b37c2016-05-05 11:44:35 -07001194 if (type == MEDIA_TYPE_DATA) {
1195 // Check for SCTP, but also for RTP for RTP-based data channels.
1196 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1197 if (secure_transport) {
1198 // Most likely scenarios first.
1199 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1200 IsPlainRtp(protocol);
1201 } else {
1202 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1203 }
1204 }
1205
1206 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1207 // JSEP specifies.
1208 if (secure_transport) {
1209 // Most likely scenarios first.
1210 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1211 } else {
1212 return IsPlainRtp(protocol);
1213 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214}
1215
1216static void SetMediaProtocol(bool secure_transport,
1217 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001218 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001220 else if (secure_transport)
1221 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 else
1223 desc->set_protocol(kMediaProtocolAvpf);
1224}
1225
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001226// Gets the TransportInfo of the given |content_name| from the
1227// |current_description|. If doesn't exist, returns a new one.
1228static const TransportDescription* GetTransportDescription(
1229 const std::string& content_name,
1230 const SessionDescription* current_description) {
1231 const TransportDescription* desc = NULL;
1232 if (current_description) {
1233 const TransportInfo* info =
1234 current_description->GetTransportInfoByName(content_name);
1235 if (info) {
1236 desc = &info->description;
1237 }
1238 }
1239 return desc;
1240}
1241
1242// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001243static bool IsDtlsActive(const ContentInfo* content,
1244 const SessionDescription* current_description) {
1245 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001246 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001247 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001248
zhihuang1c378ed2017-08-17 14:10:50 -07001249 size_t msection_index = content - &current_description->contents()[0];
1250
1251 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001252 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001253 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001254
zhihuang1c378ed2017-08-17 14:10:50 -07001255 return current_description->transport_infos()[msection_index]
1256 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001257}
1258
Steve Anton8ffb9c32017-08-31 15:45:38 -07001259void MediaDescriptionOptions::AddAudioSender(
1260 const std::string& track_id,
1261 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001262 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001263 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001264}
1265
Steve Anton8ffb9c32017-08-31 15:45:38 -07001266void MediaDescriptionOptions::AddVideoSender(
1267 const std::string& track_id,
1268 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001269 const std::vector<RidDescription>& rids,
1270 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001271 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001272 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001273 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1274 << "RIDs are the compliant way to indicate simulcast.";
1275 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1276 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1277 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001278}
1279
zhihuang1c378ed2017-08-17 14:10:50 -07001280void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1281 const std::string& stream_id) {
1282 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001283 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1284 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001285 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286}
1287
Steve Anton8ffb9c32017-08-31 15:45:38 -07001288void MediaDescriptionOptions::AddSenderInternal(
1289 const std::string& track_id,
1290 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001291 const std::vector<RidDescription>& rids,
1292 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001293 int num_sim_layers) {
1294 // TODO(steveanton): Support any number of stream ids.
1295 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001296 SenderOptions options;
1297 options.track_id = track_id;
1298 options.stream_ids = stream_ids;
1299 options.simulcast_layers = simulcast_layers;
1300 options.rids = rids;
1301 options.num_sim_layers = num_sim_layers;
1302 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303}
1304
zhihuang1c378ed2017-08-17 14:10:50 -07001305bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1306 return std::find_if(media_description_options.begin(),
1307 media_description_options.end(),
1308 [type](const MediaDescriptionOptions& t) {
1309 return t.type == type;
1310 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001311}
1312
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001314 const TransportDescriptionFactory* transport_desc_factory,
1315 rtc::UniqueRandomIdGenerator* ssrc_generator)
1316 : ssrc_generator_(ssrc_generator),
1317 transport_desc_factory_(transport_desc_factory) {
1318 RTC_DCHECK(ssrc_generator_);
1319}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320
1321MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1322 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001323 const TransportDescriptionFactory* transport_desc_factory,
1324 rtc::UniqueRandomIdGenerator* ssrc_generator)
1325 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001326 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1327 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001329 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001330 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1331 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001332 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001333}
1334
ossudedfd282016-06-14 07:12:39 -07001335const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1336 const {
ossu075af922016-06-14 03:29:38 -07001337 return audio_sendrecv_codecs_;
1338}
1339
1340const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1341 return audio_send_codecs_;
1342}
1343
1344const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1345 return audio_recv_codecs_;
1346}
1347
1348void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001349 const AudioCodecs& send_codecs,
1350 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001351 audio_send_codecs_ = send_codecs;
1352 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001353 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001354}
1355
Amit Hilbuch77938e62018-12-21 09:23:38 -08001356static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1357 RTC_DCHECK(extensions);
1358 // Unified Plan also offers the MID and RID header extensions.
1359 extensions->push_back(webrtc::RtpExtension(
1360 webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
1361 extensions->push_back(webrtc::RtpExtension(
1362 webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRidDefaultId));
1363 extensions->push_back(
1364 webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri,
1365 webrtc::RtpExtension::kRepairedRidDefaultId));
1366}
1367
1368RtpHeaderExtensions
1369MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1370 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1371 if (is_unified_plan_) {
1372 AddUnifiedPlanExtensions(&extensions);
1373 }
1374
1375 return extensions;
1376}
1377
1378RtpHeaderExtensions
1379MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1380 RtpHeaderExtensions extensions = video_rtp_extensions_;
1381 if (is_unified_plan_) {
1382 AddUnifiedPlanExtensions(&extensions);
1383 }
1384
1385 return extensions;
1386}
1387
Steve Anton6fe1fba2018-12-11 10:15:23 -08001388std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001389 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001390 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001391 // Must have options for each existing section.
1392 if (current_description) {
1393 RTC_DCHECK_LE(current_description->contents().size(),
1394 session_options.media_description_options.size());
1395 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001396
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001397 IceCredentialsIterator ice_credentials(
1398 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001399
1400 std::vector<const ContentInfo*> current_active_contents;
1401 if (current_description) {
1402 current_active_contents =
1403 GetActiveContents(*current_description, session_options);
1404 }
1405
1406 StreamParamsVec current_streams =
1407 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001408
zhihuang1c378ed2017-08-17 14:10:50 -07001409 AudioCodecs offer_audio_codecs;
1410 VideoCodecs offer_video_codecs;
1411 DataCodecs offer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001412 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001413 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001414
zhihuang1c378ed2017-08-17 14:10:50 -07001415 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001417 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001418 }
zhihuang1c378ed2017-08-17 14:10:50 -07001419 FilterDataCodecs(&offer_data_codecs,
1420 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001421
1422 RtpHeaderExtensions audio_rtp_extensions;
1423 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001424 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1425 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426
Steve Anton5c72e712018-12-10 14:25:30 -08001427 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001428
zhihuang1c378ed2017-08-17 14:10:50 -07001429 // Iterate through the media description options, matching with existing media
1430 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001431 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001432 for (const MediaDescriptionOptions& media_description_options :
1433 session_options.media_description_options) {
1434 const ContentInfo* current_content = nullptr;
1435 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001436 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001437 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001438 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001439 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001440 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001441 media_description_options.type));
1442 }
1443 switch (media_description_options.type) {
1444 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001445 if (!AddAudioContentForOffer(
1446 media_description_options, session_options, current_content,
1447 current_description, audio_rtp_extensions, offer_audio_codecs,
1448 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001449 return nullptr;
1450 }
1451 break;
1452 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001453 if (!AddVideoContentForOffer(
1454 media_description_options, session_options, current_content,
1455 current_description, video_rtp_extensions, offer_video_codecs,
1456 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001457 return nullptr;
1458 }
1459 break;
1460 case MEDIA_TYPE_DATA:
1461 if (!AddDataContentForOffer(media_description_options, session_options,
1462 current_content, current_description,
1463 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001464 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001465 return nullptr;
1466 }
1467 break;
1468 default:
1469 RTC_NOTREACHED();
1470 }
1471 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001472 }
1473
1474 // Bundle the contents together, if we've been asked to do so, and update any
1475 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001476 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001477 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001478 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001479 if (content.rejected) {
1480 continue;
1481 }
zhihuang1c378ed2017-08-17 14:10:50 -07001482 // TODO(deadbeef): There are conditions that make bundling two media
1483 // descriptions together illegal. For example, they use the same payload
1484 // type to represent different codecs, or same IDs for different header
1485 // extensions. We need to detect this and not try to bundle those media
1486 // descriptions together.
1487 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001488 }
Steve Anton2bed3972019-01-04 17:04:30 -08001489 if (!offer_bundle.content_names().empty()) {
1490 offer->AddGroup(offer_bundle);
1491 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1492 RTC_LOG(LS_ERROR)
1493 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1494 return nullptr;
1495 }
1496 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1497 RTC_LOG(LS_ERROR)
1498 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1499 return nullptr;
1500 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501 }
1502 }
Steve Antone831b8c2018-02-01 12:22:16 -08001503
1504 // The following determines how to signal MSIDs to ensure compatibility with
1505 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001506 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001507 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1508 // Plan answerers will look at a=msid and Plan B answerers will look at the
1509 // a=ssrc MSID line.
1510 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1511 cricket::kMsidSignalingSsrcAttribute);
1512 } else {
1513 // Plan B always signals MSID using a=ssrc lines.
1514 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1515 }
1516
Johannes Kron89f874e2018-11-12 10:25:48 +01001517 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1518
Steve Anton6fe1fba2018-12-11 10:15:23 -08001519 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001520}
1521
Steve Anton6fe1fba2018-12-11 10:15:23 -08001522std::unique_ptr<SessionDescription>
1523MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001524 const SessionDescription* offer,
1525 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001527 if (!offer) {
1528 return nullptr;
1529 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001530
Steve Anton5c72e712018-12-10 14:25:30 -08001531 // Must have options for exactly as many sections as in the offer.
1532 RTC_DCHECK_EQ(offer->contents().size(),
1533 session_options.media_description_options.size());
1534
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001535 IceCredentialsIterator ice_credentials(
1536 session_options.pooled_ice_credentials);
1537
Steve Anton5c72e712018-12-10 14:25:30 -08001538 std::vector<const ContentInfo*> current_active_contents;
1539 if (current_description) {
1540 current_active_contents =
1541 GetActiveContents(*current_description, session_options);
1542 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543
Steve Anton5c72e712018-12-10 14:25:30 -08001544 StreamParamsVec current_streams =
1545 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001546
zhihuang1c378ed2017-08-17 14:10:50 -07001547 // Get list of all possible codecs that respects existing payload type
1548 // mappings and uses a single payload type space.
1549 //
1550 // Note that these lists may be further filtered for each m= section; this
1551 // step is done just to establish the payload type mappings shared by all
1552 // sections.
1553 AudioCodecs answer_audio_codecs;
1554 VideoCodecs answer_video_codecs;
1555 DataCodecs answer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001556 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001557 &answer_video_codecs, &answer_data_codecs);
1558
1559 if (!session_options.vad_enabled) {
1560 // If application doesn't want CN codecs in answer.
1561 StripCNCodecs(&answer_audio_codecs);
1562 }
1563 FilterDataCodecs(&answer_data_codecs,
1564 session_options.data_channel_type == DCT_SCTP);
1565
Steve Anton5c72e712018-12-10 14:25:30 -08001566 auto answer = absl::make_unique<SessionDescription>();
1567
1568 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1569 // group in the answer with the appropriate content names.
1570 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1571 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1572 // Transport info shared by the bundle group.
1573 std::unique_ptr<TransportInfo> bundle_transport;
1574
1575 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1576
zhihuang1c378ed2017-08-17 14:10:50 -07001577 // Iterate through the media description options, matching with existing
1578 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001579 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001580 for (const MediaDescriptionOptions& media_description_options :
1581 session_options.media_description_options) {
1582 const ContentInfo* offer_content = &offer->contents()[msection_index];
1583 // Media types and MIDs must match between the remote offer and the
1584 // MediaDescriptionOptions.
1585 RTC_DCHECK(
1586 IsMediaContentOfType(offer_content, media_description_options.type));
1587 RTC_DCHECK(media_description_options.mid == offer_content->name);
1588 const ContentInfo* current_content = nullptr;
1589 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001590 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001591 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001592 }
zhihuang1c378ed2017-08-17 14:10:50 -07001593 switch (media_description_options.type) {
1594 case MEDIA_TYPE_AUDIO:
1595 if (!AddAudioContentForAnswer(
1596 media_description_options, session_options, offer_content,
1597 offer, current_content, current_description,
1598 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001599 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001600 return nullptr;
1601 }
1602 break;
1603 case MEDIA_TYPE_VIDEO:
1604 if (!AddVideoContentForAnswer(
1605 media_description_options, session_options, offer_content,
1606 offer, current_content, current_description,
1607 bundle_transport.get(), answer_video_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_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001613 if (!AddDataContentForAnswer(
1614 media_description_options, session_options, offer_content,
1615 offer, current_content, current_description,
1616 bundle_transport.get(), answer_data_codecs, &current_streams,
1617 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001618 return nullptr;
1619 }
1620 break;
1621 default:
1622 RTC_NOTREACHED();
1623 }
1624 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001625 // See if we can add the newly generated m= section to the BUNDLE group in
1626 // the answer.
1627 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001628 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001629 offer_bundle->HasContentName(added.name)) {
1630 answer_bundle.AddContentName(added.name);
1631 bundle_transport.reset(
1632 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 }
1635
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001636 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1637 // it's empty. RFC5888 says:
1638 //
1639 // A SIP entity that receives an offer that contains an "a=group" line
1640 // with semantics that are understood MUST return an answer that
1641 // contains an "a=group" line with the same semantics.
1642 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001643 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001644 }
deadbeefb7892532017-02-22 19:35:18 -08001645
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001646 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001647 // Share the same ICE credentials and crypto params across all contents,
1648 // as BUNDLE requires.
1649 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001650 RTC_LOG(LS_ERROR)
1651 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001652 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001653 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001654
deadbeefb7892532017-02-22 19:35:18 -08001655 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001656 RTC_LOG(LS_ERROR)
1657 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001658 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001659 }
1660 }
1661
Steve Antone831b8c2018-02-01 12:22:16 -08001662 // The following determines how to signal MSIDs to ensure compatibility with
1663 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001664 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001665 // Unified Plan needs to look at what the offer included to find the most
1666 // compatible answer.
1667 if (offer->msid_signaling() == 0) {
1668 // We end up here in one of three cases:
1669 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1670 // matter what we pick here.
1671 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1672 // it also doesn't matter what we pick here.
1673 // 3. Media that's either sendonly or inactive from the remote endpoint.
1674 // We don't have any information to say whether the endpoint is Plan B
1675 // or Unified Plan, so be conservative and send both.
1676 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1677 cricket::kMsidSignalingSsrcAttribute);
1678 } else if (offer->msid_signaling() ==
1679 (cricket::kMsidSignalingMediaSection |
1680 cricket::kMsidSignalingSsrcAttribute)) {
1681 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1682 // probably talking to a Unified Plan endpoint so respond with just
1683 // a=msid.
1684 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1685 } else {
1686 // Otherwise, it's clear which method the offerer is using so repeat that
1687 // back to them.
1688 answer->set_msid_signaling(offer->msid_signaling());
1689 }
1690 } else {
1691 // Plan B always signals MSID using a=ssrc lines.
1692 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1693 }
1694
Steve Anton6fe1fba2018-12-11 10:15:23 -08001695 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696}
1697
ossu075af922016-06-14 03:29:38 -07001698const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1699 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001700 switch (direction) {
1701 // If stream is inactive - generate list as if sendrecv.
1702 case RtpTransceiverDirection::kSendRecv:
1703 case RtpTransceiverDirection::kInactive:
1704 return audio_sendrecv_codecs_;
1705 case RtpTransceiverDirection::kSendOnly:
1706 return audio_send_codecs_;
1707 case RtpTransceiverDirection::kRecvOnly:
1708 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001709 }
Steve Anton1d03a752017-11-27 14:30:09 -08001710 RTC_NOTREACHED();
1711 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001712}
1713
1714const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1715 const RtpTransceiverDirection& offer,
1716 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001717 switch (answer) {
1718 // For inactive and sendrecv answers, generate lists as if we were to accept
1719 // the offer's direction. See RFC 3264 Section 6.1.
1720 case RtpTransceiverDirection::kSendRecv:
1721 case RtpTransceiverDirection::kInactive:
1722 return GetAudioCodecsForOffer(
1723 webrtc::RtpTransceiverDirectionReversed(offer));
1724 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001725 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001726 case RtpTransceiverDirection::kRecvOnly:
1727 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001728 }
Steve Anton1d03a752017-11-27 14:30:09 -08001729 RTC_NOTREACHED();
1730 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001731}
1732
Steve Anton5c72e712018-12-10 14:25:30 -08001733void MergeCodecsFromDescription(
1734 const std::vector<const ContentInfo*>& current_active_contents,
1735 AudioCodecs* audio_codecs,
1736 VideoCodecs* video_codecs,
1737 DataCodecs* data_codecs,
1738 UsedPayloadTypes* used_pltypes) {
1739 for (const ContentInfo* content : current_active_contents) {
1740 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001741 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001742 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001743 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001744 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001745 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001746 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001747 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001748 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001749 const DataContentDescription* data =
Steve Anton5c72e712018-12-10 14:25:30 -08001750 content->media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001751 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1752 }
1753 }
1754}
1755
1756// Getting codecs for an offer involves these steps:
1757//
1758// 1. Construct payload type -> codec mappings for current description.
1759// 2. Add any reference codecs that weren't already present
1760// 3. For each individual media description (m= section), filter codecs based
1761// on the directional attribute (happens in another method).
1762void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001763 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 AudioCodecs* audio_codecs,
1765 VideoCodecs* video_codecs,
1766 DataCodecs* data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001768 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1769 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001770 UsedPayloadTypes used_pltypes;
1771 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1772 video_codecs, data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773
Steve Anton5c72e712018-12-10 14:25:30 -08001774 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001775 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1776 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1777 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1778}
1779
1780// Getting codecs for an answer involves these steps:
1781//
1782// 1. Construct payload type -> codec mappings for current description.
1783// 2. Add any codecs from the offer that weren't already present.
1784// 3. Add any remaining codecs that weren't already present.
1785// 4. For each individual media description (m= section), filter codecs based
1786// on the directional attribute (happens in another method).
1787void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001788 const std::vector<const ContentInfo*>& current_active_contents,
1789 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001790 AudioCodecs* audio_codecs,
1791 VideoCodecs* video_codecs,
1792 DataCodecs* data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001793 // First - get all codecs from the current description if the media type
1794 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1795 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001796 UsedPayloadTypes used_pltypes;
1797 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1798 video_codecs, data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001799
1800 // Second - filter out codecs that we don't support at all and should ignore.
1801 AudioCodecs filtered_offered_audio_codecs;
1802 VideoCodecs filtered_offered_video_codecs;
1803 DataCodecs filtered_offered_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001804 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001805 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1806 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001807 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001808 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1809 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1810 filtered_offered_audio_codecs,
1811 offered_audio_codec, nullptr) &&
1812 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1813 offered_audio_codec, nullptr)) {
1814 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1815 }
1816 }
1817 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1818 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001819 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001820 for (const VideoCodec& offered_video_codec : video->codecs()) {
1821 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1822 filtered_offered_video_codecs,
1823 offered_video_codec, nullptr) &&
1824 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1825 offered_video_codec, nullptr)) {
1826 filtered_offered_video_codecs.push_back(offered_video_codec);
1827 }
1828 }
1829 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1830 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001831 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001832 for (const DataCodec& offered_data_codec : data->codecs()) {
1833 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1834 filtered_offered_data_codecs,
1835 offered_data_codec, nullptr) &&
1836 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1837 offered_data_codec, nullptr)) {
1838 filtered_offered_data_codecs.push_back(offered_data_codec);
1839 }
1840 }
1841 }
1842 }
1843
Steve Anton5c72e712018-12-10 14:25:30 -08001844 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001845 // |remote_offer|.
1846 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1847 &used_pltypes);
1848 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1849 &used_pltypes);
1850 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1851 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001852}
1853
1854void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001855 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001856 RtpHeaderExtensions* offer_audio_extensions,
1857 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001858 // All header extensions allocated from the same range to avoid potential
1859 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001861 RtpHeaderExtensions all_regular_extensions;
1862 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863
1864 // First - get all extensions from the current description if the media type
1865 // is used.
1866 // Add them to |used_ids| so the local ids are not reused if a new media
1867 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001868 for (const ContentInfo* content : current_active_contents) {
1869 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1870 const AudioContentDescription* audio =
1871 content->media_description()->as_audio();
1872 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1873 &all_regular_extensions, &all_encrypted_extensions,
1874 &used_ids);
1875 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1876 const VideoContentDescription* video =
1877 content->media_description()->as_video();
1878 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1879 &all_regular_extensions, &all_encrypted_extensions,
1880 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881 }
1882 }
1883
Steve Anton5c72e712018-12-10 14:25:30 -08001884 // Add our default RTP header extensions that are not in the current
1885 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001886 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1887 &all_regular_extensions, &all_encrypted_extensions,
1888 &used_ids);
1889 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1890 &all_regular_extensions, &all_encrypted_extensions,
1891 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001892
jbauch5869f502017-06-29 12:31:36 -07001893 // TODO(jbauch): Support adding encrypted header extensions to existing
1894 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001895 if (enable_encrypted_rtp_header_extensions_ &&
1896 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001897 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1898 &all_encrypted_extensions, &used_ids);
1899 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1900 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001901 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902}
1903
1904bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001905 const std::string& content_name,
1906 const TransportOptions& transport_options,
1907 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001908 SessionDescription* offer_desc,
1909 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001910 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001911 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 const TransportDescription* current_tdesc =
1913 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001914 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001915 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1916 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001917 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001918 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1919 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001920 }
Steve Anton06817cd2018-12-18 15:55:30 -08001921 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1922 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923}
1924
Steve Anton1a9d3c32018-12-10 17:18:54 -08001925std::unique_ptr<TransportDescription>
1926MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001927 const std::string& content_name,
1928 const SessionDescription* offer_desc,
1929 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001930 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001931 bool require_transport_attributes,
1932 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001933 if (!transport_desc_factory_)
1934 return NULL;
1935 const TransportDescription* offer_tdesc =
1936 GetTransportDescription(content_name, offer_desc);
1937 const TransportDescription* current_tdesc =
1938 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001939 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1940 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001941 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942}
1943
1944bool MediaSessionDescriptionFactory::AddTransportAnswer(
1945 const std::string& content_name,
1946 const TransportDescription& transport_desc,
1947 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001948 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949 return true;
1950}
1951
zhihuang1c378ed2017-08-17 14:10:50 -07001952// |audio_codecs| = set of all possible codecs that can be used, with correct
1953// payload type mappings
1954//
1955// |supported_audio_codecs| = set of codecs that are supported for the direction
1956// of this m= section
1957//
1958// acd->codecs() = set of previously negotiated codecs for this m= section
1959//
1960// The payload types should come from audio_codecs, but the order should come
1961// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1962// change existing codec priority, and that new codecs are added with the right
1963// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001964bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001965 const MediaDescriptionOptions& media_description_options,
1966 const MediaSessionOptions& session_options,
1967 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001968 const SessionDescription* current_description,
1969 const RtpHeaderExtensions& audio_rtp_extensions,
1970 const AudioCodecs& audio_codecs,
1971 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001972 SessionDescription* desc,
1973 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001974 // Filter audio_codecs (which includes all codecs, with correctly remapped
1975 // payload types) based on transceiver direction.
1976 const AudioCodecs& supported_audio_codecs =
1977 GetAudioCodecsForOffer(media_description_options.direction);
1978
1979 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001980 // Add the codecs from current content if it exists and is not rejected nor
1981 // recycled.
1982 if (current_content && !current_content->rejected &&
1983 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001984 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001985 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001986 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001987 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001988 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1989 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001990 filtered_codecs.push_back(codec);
1991 }
1992 }
1993 }
1994 // Add other supported audio codecs.
1995 AudioCodec found_codec;
1996 for (const AudioCodec& codec : supported_audio_codecs) {
1997 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1998 codec, &found_codec) &&
1999 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2000 codec, nullptr)) {
2001 // Use the |found_codec| from |audio_codecs| because it has the correctly
2002 // mapped payload type.
2003 filtered_codecs.push_back(found_codec);
2004 }
2005 }
deadbeef44f08192015-12-15 16:20:09 -08002006
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002007 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002008 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2009 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002010
kwiberg31022942016-03-11 14:18:21 -08002011 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002012 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002013 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2014 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002015 if (!CreateMediaContentOffer(media_description_options, session_options,
2016 filtered_codecs, sdes_policy,
2017 GetCryptos(current_content), crypto_suites,
2018 audio_rtp_extensions, ssrc_generator_,
2019 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002020 return false;
2021 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002022
2023 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2024 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002025
Steve Anton4e70a722017-11-28 14:57:10 -08002026 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002027
Steve Anton5adfafd2017-12-20 16:34:00 -08002028 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002029 media_description_options.stopped, audio.release());
2030 if (!AddTransportOffer(media_description_options.mid,
2031 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002032 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002033 return false;
2034 }
2035
2036 return true;
2037}
2038
2039bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002040 const MediaDescriptionOptions& media_description_options,
2041 const MediaSessionOptions& session_options,
2042 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002043 const SessionDescription* current_description,
2044 const RtpHeaderExtensions& video_rtp_extensions,
2045 const VideoCodecs& video_codecs,
2046 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002047 SessionDescription* desc,
2048 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002049 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002050 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2051 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052
kwiberg31022942016-03-11 14:18:21 -08002053 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002054 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002055 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2056 &crypto_suites);
2057
2058 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002059 // Add the codecs from current content if it exists and is not rejected nor
2060 // recycled.
2061 if (current_content && !current_content->rejected &&
2062 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002063 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002064 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002065 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002066 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002067 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002068 nullptr)) {
2069 filtered_codecs.push_back(codec);
2070 }
2071 }
2072 }
2073 // Add other supported video codecs.
2074 VideoCodec found_codec;
2075 for (const VideoCodec& codec : video_codecs_) {
2076 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2077 &found_codec) &&
2078 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2079 nullptr)) {
2080 // Use the |found_codec| from |video_codecs| because it has the correctly
2081 // mapped payload type.
2082 filtered_codecs.push_back(found_codec);
2083 }
2084 }
2085
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002086 if (!CreateMediaContentOffer(media_description_options, session_options,
2087 filtered_codecs, sdes_policy,
2088 GetCryptos(current_content), crypto_suites,
2089 video_rtp_extensions, ssrc_generator_,
2090 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002091 return false;
2092 }
2093
zhihuang1c378ed2017-08-17 14:10:50 -07002094 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002095
2096 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2097 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002098
Steve Anton4e70a722017-11-28 14:57:10 -08002099 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002100
Steve Anton5adfafd2017-12-20 16:34:00 -08002101 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002102 media_description_options.stopped, video.release());
2103 if (!AddTransportOffer(media_description_options.mid,
2104 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002105 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002106 return false;
2107 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002108 return true;
2109}
2110
2111bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002112 const MediaDescriptionOptions& media_description_options,
2113 const MediaSessionOptions& session_options,
2114 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002115 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07002116 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002117 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002118 SessionDescription* desc,
2119 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002120 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2121
kwiberg31022942016-03-11 14:18:21 -08002122 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07002123 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2124 // If the DataChannel type is not specified, use the DataChannel type in
2125 // the current description.
2126 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002127 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002128 is_sctp = (current_content->media_description()->protocol() ==
2129 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002130 }
deadbeef44f08192015-12-15 16:20:09 -08002131
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002132 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002133 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2134 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002135 std::vector<std::string> crypto_suites;
2136 if (is_sctp) {
2137 // SDES doesn't make sense for SCTP, so we disable it, and we only
2138 // get SDES crypto suites for RTP-based data channels.
2139 sdes_policy = cricket::SEC_DISABLED;
2140 // Unlike SetMediaProtocol below, we need to set the protocol
2141 // before we call CreateMediaContentOffer. Otherwise,
2142 // CreateMediaContentOffer won't know this is SCTP and will
2143 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002144 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2145 // it's safe to do so. Older versions of webrtc would reject these
2146 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002147 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2148 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002149 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002150 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002151 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002152 }
2153
zhihuang1c378ed2017-08-17 14:10:50 -07002154 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002155 if (!CreateMediaContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002156 media_description_options, session_options, data_codecs, sdes_policy,
2157 GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002158 ssrc_generator_, current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002159 return false;
2160 }
2161
2162 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002163 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002164 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002165 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002166 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002167 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002168 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002169 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002170 }
zhihuang1c378ed2017-08-17 14:10:50 -07002171 if (!AddTransportOffer(media_description_options.mid,
2172 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002173 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002174 return false;
2175 }
2176 return true;
2177}
2178
zhihuang1c378ed2017-08-17 14:10:50 -07002179// |audio_codecs| = set of all possible codecs that can be used, with correct
2180// payload type mappings
2181//
2182// |supported_audio_codecs| = set of codecs that are supported for the direction
2183// of this m= section
2184//
2185// acd->codecs() = set of previously negotiated codecs for this m= section
2186//
2187// The payload types should come from audio_codecs, but the order should come
2188// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2189// change existing codec priority, and that new codecs are added with the right
2190// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002191bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002192 const MediaDescriptionOptions& media_description_options,
2193 const MediaSessionOptions& session_options,
2194 const ContentInfo* offer_content,
2195 const SessionDescription* offer_description,
2196 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002197 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002198 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002199 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002200 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002201 SessionDescription* answer,
2202 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002203 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002204 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002205 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002206
Steve Anton1a9d3c32018-12-10 17:18:54 -08002207 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002208 media_description_options.mid, offer_description,
2209 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002210 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002211 if (!audio_transport) {
2212 return false;
2213 }
2214
zhihuang1c378ed2017-08-17 14:10:50 -07002215 // Pick codecs based on the requested communications direction in the offer
2216 // and the selected direction in the answer.
2217 // Note these will be filtered one final time in CreateMediaContentAnswer.
2218 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002219 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002220 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002221 AudioCodecs supported_audio_codecs =
2222 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2223
2224 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002225 // Add the codecs from current content if it exists and is not rejected nor
2226 // recycled.
2227 if (current_content && !current_content->rejected &&
2228 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002229 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002230 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002231 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002232 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002233 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2234 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002235 filtered_codecs.push_back(codec);
2236 }
2237 }
2238 }
2239 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002240 for (const AudioCodec& codec : supported_audio_codecs) {
2241 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002242 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002243 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2244 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002245 // We should use the local codec with local parameters and the codec id
2246 // would be correctly mapped in |NegotiateCodecs|.
2247 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002248 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002249 }
2250
zhihuang1c378ed2017-08-17 14:10:50 -07002251 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2252 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002253 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002254 new AudioContentDescription());
2255 // Do not require or create SDES cryptos if DTLS is used.
2256 cricket::SecurePolicy sdes_policy =
2257 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2258 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002259 offer_audio_description, media_description_options, session_options,
2260 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002261 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002262 enable_encrypted_rtp_header_extensions_, current_streams,
2263 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002264 return false; // Fails the session setup.
2265 }
2266
deadbeefb7892532017-02-22 19:35:18 -08002267 bool secure = bundle_transport ? bundle_transport->description.secure()
2268 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002269 bool rejected = media_description_options.stopped ||
2270 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002271 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2272 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002273 if (!AddTransportAnswer(media_description_options.mid,
2274 *(audio_transport.get()), answer)) {
2275 return false;
2276 }
2277
2278 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002279 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2280 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002281 }
2282
zhihuang1c378ed2017-08-17 14:10:50 -07002283 answer->AddContent(media_description_options.mid, offer_content->type,
2284 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002285 return true;
2286}
2287
2288bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002289 const MediaDescriptionOptions& media_description_options,
2290 const MediaSessionOptions& session_options,
2291 const ContentInfo* offer_content,
2292 const SessionDescription* offer_description,
2293 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002294 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002295 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002296 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002297 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002298 SessionDescription* answer,
2299 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002300 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002301 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002302 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002303
Steve Anton1a9d3c32018-12-10 17:18:54 -08002304 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002305 media_description_options.mid, offer_description,
2306 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002307 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002308 if (!video_transport) {
2309 return false;
2310 }
2311
zhihuang1c378ed2017-08-17 14:10:50 -07002312 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002313 // Add the codecs from current content if it exists and is not rejected nor
2314 // recycled.
2315 if (current_content && !current_content->rejected &&
2316 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002317 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002318 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002319 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002320 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002321 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002322 nullptr)) {
2323 filtered_codecs.push_back(codec);
2324 }
2325 }
2326 }
2327 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002328 for (const VideoCodec& codec : video_codecs_) {
2329 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002330 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002331 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2332 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002333 // We should use the local codec with local parameters and the codec id
2334 // would be correctly mapped in |NegotiateCodecs|.
2335 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002336 }
2337 }
2338
2339 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2340 session_options.bundle_enabled;
2341
kwiberg31022942016-03-11 14:18:21 -08002342 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002343 new VideoContentDescription());
2344 // Do not require or create SDES cryptos if DTLS is used.
2345 cricket::SecurePolicy sdes_policy =
2346 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002347 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002348 offer_video_description, media_description_options, session_options,
2349 filtered_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002350 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002351 enable_encrypted_rtp_header_extensions_, current_streams,
2352 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002353 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002354 }
deadbeefb7892532017-02-22 19:35:18 -08002355 bool secure = bundle_transport ? bundle_transport->description.secure()
2356 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002357 bool rejected = media_description_options.stopped ||
2358 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002359 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2360 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002361 if (!AddTransportAnswer(media_description_options.mid,
2362 *(video_transport.get()), answer)) {
2363 return false;
2364 }
2365
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002366 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002367 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002368 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002369 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2370 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002371 }
zhihuang1c378ed2017-08-17 14:10:50 -07002372 answer->AddContent(media_description_options.mid, offer_content->type,
2373 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002374 return true;
2375}
2376
2377bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002378 const MediaDescriptionOptions& media_description_options,
2379 const MediaSessionOptions& session_options,
2380 const ContentInfo* offer_content,
2381 const SessionDescription* offer_description,
2382 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002383 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002384 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002385 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002386 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002387 SessionDescription* answer,
2388 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002389 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002390 media_description_options.mid, offer_description,
2391 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002392 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002393 if (!data_transport) {
2394 return false;
2395 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002396
kwiberg31022942016-03-11 14:18:21 -08002397 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002398 new DataContentDescription());
2399 // Do not require or create SDES cryptos if DTLS is used.
2400 cricket::SecurePolicy sdes_policy =
2401 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002402 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2403 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002404 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2405 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002406 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002407 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002408 offer_data_description, media_description_options, session_options,
2409 data_codecs, sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002410 RtpHeaderExtensions(), ssrc_generator_,
2411 enable_encrypted_rtp_header_extensions_, current_streams,
2412 bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002413 return false; // Fails the session setup.
2414 }
2415
zstein4b2e0822017-02-17 19:48:38 -08002416 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002417 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2418 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2419
deadbeefb7892532017-02-22 19:35:18 -08002420 bool secure = bundle_transport ? bundle_transport->description.secure()
2421 : data_transport->secure();
2422
zhihuang1c378ed2017-08-17 14:10:50 -07002423 bool rejected = session_options.data_channel_type == DCT_NONE ||
2424 media_description_options.stopped ||
2425 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002426 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2427 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002428 if (!AddTransportAnswer(media_description_options.mid,
2429 *(data_transport.get()), answer)) {
2430 return false;
2431 }
2432
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002433 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002434 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002435 } else {
2436 // RFC 3264
2437 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002438 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002439 }
zhihuang1c378ed2017-08-17 14:10:50 -07002440 answer->AddContent(media_description_options.mid, offer_content->type,
2441 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002442 return true;
2443}
2444
zhihuang1c378ed2017-08-17 14:10:50 -07002445void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2446 audio_sendrecv_codecs_.clear();
2447 all_audio_codecs_.clear();
2448 // Compute the audio codecs union.
2449 for (const AudioCodec& send : audio_send_codecs_) {
2450 all_audio_codecs_.push_back(send);
2451 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2452 send, nullptr)) {
2453 // It doesn't make sense to have an RTX codec we support sending but not
2454 // receiving.
2455 RTC_DCHECK(!IsRtxCodec(send));
2456 }
2457 }
2458 for (const AudioCodec& recv : audio_recv_codecs_) {
2459 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2460 recv, nullptr)) {
2461 all_audio_codecs_.push_back(recv);
2462 }
2463 }
2464 // Use NegotiateCodecs to merge our codec lists, since the operation is
2465 // essentially the same. Put send_codecs as the offered_codecs, which is the
2466 // order we'd like to follow. The reasoning is that encoding is usually more
2467 // expensive than decoding, and prioritizing a codec in the send list probably
2468 // means it's a codec we can handle efficiently.
2469 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2470 &audio_sendrecv_codecs_);
2471}
2472
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002473bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002474 return (content && (content->type == MediaProtocolType::kRtp ||
2475 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476}
2477
2478bool IsAudioContent(const ContentInfo* content) {
2479 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2480}
2481
2482bool IsVideoContent(const ContentInfo* content) {
2483 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2484}
2485
2486bool IsDataContent(const ContentInfo* content) {
2487 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2488}
2489
deadbeef0ed85b22016-02-23 17:24:52 -08002490const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2491 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002492 for (const ContentInfo& content : contents) {
2493 if (IsMediaContentOfType(&content, media_type)) {
2494 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002495 }
2496 }
deadbeef0ed85b22016-02-23 17:24:52 -08002497 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498}
2499
2500const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2501 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2502}
2503
2504const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2505 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2506}
2507
2508const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2509 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2510}
2511
Steve Antonad7bffc2018-01-22 10:21:56 -08002512const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2513 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002514 if (sdesc == nullptr) {
2515 return nullptr;
2516 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517
2518 return GetFirstMediaContent(sdesc->contents(), media_type);
2519}
2520
2521const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2522 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2523}
2524
2525const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2526 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2527}
2528
2529const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2530 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2531}
2532
2533const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002534 const SessionDescription* sdesc,
2535 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002536 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002537 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002538}
2539
2540const AudioContentDescription* GetFirstAudioContentDescription(
2541 const SessionDescription* sdesc) {
2542 return static_cast<const AudioContentDescription*>(
2543 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2544}
2545
2546const VideoContentDescription* GetFirstVideoContentDescription(
2547 const SessionDescription* sdesc) {
2548 return static_cast<const VideoContentDescription*>(
2549 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2550}
2551
2552const DataContentDescription* GetFirstDataContentDescription(
2553 const SessionDescription* sdesc) {
2554 return static_cast<const DataContentDescription*>(
2555 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2556}
2557
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002558//
2559// Non-const versions of the above functions.
2560//
2561
Steve Anton36b29d12017-10-30 09:57:42 -07002562ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002563 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002564 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002565 if (IsMediaContentOfType(&content, media_type)) {
2566 return &content;
2567 }
2568 }
2569 return nullptr;
2570}
2571
Steve Anton36b29d12017-10-30 09:57:42 -07002572ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002573 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2574}
2575
Steve Anton36b29d12017-10-30 09:57:42 -07002576ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002577 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2578}
2579
Steve Anton36b29d12017-10-30 09:57:42 -07002580ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002581 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2582}
2583
Steve Antonad7bffc2018-01-22 10:21:56 -08002584ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2585 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002586 if (sdesc == nullptr) {
2587 return nullptr;
2588 }
2589
Steve Anton36b29d12017-10-30 09:57:42 -07002590 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002591}
2592
2593ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2594 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2595}
2596
2597ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2598 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2599}
2600
2601ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2602 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2603}
2604
2605MediaContentDescription* GetFirstMediaContentDescription(
2606 SessionDescription* sdesc,
2607 MediaType media_type) {
2608 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002609 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002610}
2611
2612AudioContentDescription* GetFirstAudioContentDescription(
2613 SessionDescription* sdesc) {
2614 return static_cast<AudioContentDescription*>(
2615 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2616}
2617
2618VideoContentDescription* GetFirstVideoContentDescription(
2619 SessionDescription* sdesc) {
2620 return static_cast<VideoContentDescription*>(
2621 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2622}
2623
2624DataContentDescription* GetFirstDataContentDescription(
2625 SessionDescription* sdesc) {
2626 return static_cast<DataContentDescription*>(
2627 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2628}
2629
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630} // namespace cricket