blob: 7cc4b95f14ee682f3c77394858d137c4191af149 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/media_session.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
Elad Alon157540a2019-02-08 23:37:52 +010013#include <algorithm>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve Anton64b626b2019-01-28 17:25:26 -080021#include "absl/algorithm/container.h"
Steve Anton5c72e712018-12-10 14:25:30 -080022#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020023#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020024#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "media/base/media_constants.h"
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +020028#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "p2p/base/p2p_constants.h"
30#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020031#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/rtp_media_utils.h"
33#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/checks.h"
35#include "rtc_base/helpers.h"
36#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020037#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080038#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080041
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080042using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080043using webrtc::RtpTransceiverDirection;
44
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046
Benjamin Wrighta54daf12018-10-11 15:33:17 -070047void GetSupportedSdesCryptoSuiteNames(
48 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
49 const webrtc::CryptoOptions& crypto_options,
50 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070052 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080053 for (const auto crypto : crypto_suites) {
54 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
55 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080056}
Elad Alon157540a2019-02-08 23:37:52 +010057
terelius8c011e52016-04-26 05:28:11 -070058} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60namespace cricket {
61
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062// RTP Profile names
63// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
64// RFC4585
65const char kMediaProtocolAvpf[] = "RTP/AVPF";
66// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000067const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
68
deadbeeff3938292015-07-15 12:20:53 -070069// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
70// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071const char kMediaProtocolSavpf[] = "RTP/SAVPF";
72
deadbeef8b7e9ad2017-05-25 09:38:55 -070073// Note that the below functions support some protocol strings purely for
74// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
75// and Interoperability.
76
77static bool IsDtlsRtp(const std::string& protocol) {
78 // Most-likely values first.
79 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
80 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
81}
82
83static bool IsPlainRtp(const std::string& protocol) {
84 // Most-likely values first.
85 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
86 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
87}
88
Steve Anton1d03a752017-11-27 14:30:09 -080089static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
90 RtpTransceiverDirection offer,
91 RtpTransceiverDirection wants) {
92 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
93 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
94 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
95 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
96 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
97 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070098}
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100static bool IsMediaContentOfType(const ContentInfo* content,
101 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800102 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103 return false;
104 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800105 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106}
107
Yves Gerey665174f2018-06-19 15:03:05 +0200108static bool CreateCryptoParams(int tag,
109 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700110 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700111 int key_len;
112 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200113 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
114 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return false;
116 }
jbauchcb560652016-08-04 05:20:32 -0700117
118 int master_key_len = key_len + salt_len;
119 std::string master_key;
120 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
121 return false;
122 }
123
kwiberg352444f2016-11-28 15:58:53 -0800124 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700125 std::string key = rtc::Base64::Encode(master_key);
126
Steve Anton3a66edf2018-09-10 12:57:37 -0700127 crypto_out->tag = tag;
128 crypto_out->cipher_suite = cipher;
129 crypto_out->key_params = kInline;
130 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 return true;
132}
133
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700135 CryptoParamsVec* cryptos_out) {
136 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Steve Anton3a66edf2018-09-10 12:57:37 -0700138 cryptos_out->resize(size + 1);
139 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140}
141
142void AddMediaCryptos(const CryptoParamsVec& cryptos,
143 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700144 for (const CryptoParams& crypto : cryptos) {
145 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 }
147}
148
149bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
150 MediaContentDescription* media) {
151 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700152 for (const std::string& crypto_suite : crypto_suites) {
153 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 return false;
155 }
156 }
157 AddMediaCryptos(cryptos, media);
158 return true;
159}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
zhihuang1c378ed2017-08-17 14:10:50 -0700161const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800162 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700163 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800165 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
168bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
169 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700170 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800171 auto it = absl::c_find_if(
172 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700173 if (it == cryptos.end()) {
174 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700176 *crypto_out = *it;
177 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178}
179
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700180// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
181// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700182void GetSupportedAudioSdesCryptoSuites(
183 const webrtc::CryptoOptions& crypto_options,
184 std::vector<int>* crypto_suites) {
185 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
188 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700189 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700190 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
191 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800192 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193}
194
deadbeef7914b8c2017-04-21 03:23:33 -0700195void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700196 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800197 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700198 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
199 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200}
201
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700202void GetSupportedVideoSdesCryptoSuites(
203 const webrtc::CryptoOptions& crypto_options,
204 std::vector<int>* crypto_suites) {
205 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700206 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
207 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
208 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800209 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
deadbeef7914b8c2017-04-21 03:23:33 -0700212void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700213 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800214 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700215 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedDataSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
227}
228
229void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700231 std::vector<std::string>* crypto_suite_names) {
232 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800234}
235
jbauchcb560652016-08-04 05:20:32 -0700236// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700237// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
238// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700239// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240static bool SelectCrypto(const MediaContentDescription* offer,
241 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700242 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700243 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
245 const CryptoParamsVec& cryptos = offer->cryptos();
246
Steve Anton3a66edf2018-09-10 12:57:37 -0700247 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700248 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700249 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
250 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
251 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700252 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700253 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 }
255 }
256 return false;
257}
258
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800260static StreamParamsVec GetCurrentStreamParams(
261 const std::vector<const ContentInfo*>& active_local_contents) {
262 StreamParamsVec stream_params;
263 for (const ContentInfo* content : active_local_contents) {
264 for (const StreamParams& params : content->media_description()->streams()) {
265 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 }
267 }
Steve Anton5c72e712018-12-10 14:25:30 -0800268 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269}
270
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000271// Filters the data codecs for the data channel type.
272void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
273 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700274 const char* codec_name =
275 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700276 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
277 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200278 return absl::EqualsIgnoreCase(codec.name,
279 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700280 }),
281 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000282}
283
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284template <typename IdStruct>
285class UsedIds {
286 public:
287 UsedIds(int min_allowed_id, int max_allowed_id)
288 : min_allowed_id_(min_allowed_id),
289 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200290 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291
292 // Loops through all Id in |ids| and changes its id if it is
293 // already in use by another IdStruct. Call this methods with all Id
294 // in a session description to make sure no duplicate ids exists.
295 // Note that typename Id must be a type of IdStruct.
296 template <typename Id>
297 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700298 for (const Id& id : *ids) {
299 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 }
301 }
302
303 // Finds and sets an unused id if the |idstruct| id is already in use.
304 void FindAndSetIdUsed(IdStruct* idstruct) {
305 const int original_id = idstruct->id;
306 int new_id = idstruct->id;
307
308 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
309 // If the original id is not in range - this is an id that can't be
310 // dynamically changed.
311 return;
312 }
313
314 if (IsIdUsed(original_id)) {
315 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100316 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
317 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318 idstruct->id = new_id;
319 }
320 SetIdUsed(new_id);
321 }
322
323 private:
324 // Returns the first unused id in reverse order.
325 // This hopefully reduce the risk of more collisions. We want to change the
326 // default ids as little as possible.
327 int FindUnusedId() {
328 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
329 --next_id_;
330 }
nisseede5da42017-01-12 05:15:36 -0800331 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 return next_id_;
333 }
334
Yves Gerey665174f2018-06-19 15:03:05 +0200335 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336
Yves Gerey665174f2018-06-19 15:03:05 +0200337 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338
339 const int min_allowed_id_;
340 const int max_allowed_id_;
341 int next_id_;
342 std::set<int> id_set_;
343};
344
345// Helper class used for finding duplicate RTP payload types among audio, video
346// and data codecs. When bundle is used the payload types may not collide.
347class UsedPayloadTypes : public UsedIds<Codec> {
348 public:
349 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200350 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351
352 private:
353 static const int kDynamicPayloadTypeMin = 96;
354 static const int kDynamicPayloadTypeMax = 127;
355};
356
357// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200358// audio and video extensions. Only applies to one-byte header extensions at the
359// moment. ids > 14 will always be reported as available.
360// TODO(kron): This class needs to be refactored when we start to send two-byte
361// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700362class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363 public:
364 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200365 : UsedIds<webrtc::RtpExtension>(
366 webrtc::RtpExtension::kMinId,
367 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
369 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370};
371
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
373 const SenderOptions& sender,
374 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800375 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800376 bool include_flexfec_stream,
377 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800378 StreamParams result;
379 result.id = sender.track_id;
380
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800381 // TODO(brandtr): Update when we support multistream protection.
382 if (include_flexfec_stream && sender.num_sim_layers > 1) {
383 include_flexfec_stream = false;
384 RTC_LOG(LS_WARNING)
385 << "Our FlexFEC implementation only supports protecting "
386 "a single media streams. This session has multiple "
387 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800388 }
389
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800390 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
391 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800392
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800393 result.cname = rtcp_cname;
394 result.set_stream_ids(sender.stream_ids);
395
396 return result;
397}
398
399static bool ValidateSimulcastLayers(
400 const std::vector<RidDescription>& rids,
401 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800402 return absl::c_all_of(
403 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
404 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
405 return rid.rid == layer.rid;
406 });
407 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800408}
409
410static StreamParams CreateStreamParamsForNewSenderWithRids(
411 const SenderOptions& sender,
412 const std::string& rtcp_cname) {
413 RTC_DCHECK(!sender.rids.empty());
414 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
415 << "RIDs are the compliant way to indicate simulcast.";
416 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
417 StreamParams result;
418 result.id = sender.track_id;
419 result.cname = rtcp_cname;
420 result.set_stream_ids(sender.stream_ids);
421
422 // More than one rid should be signaled.
423 if (sender.rids.size() > 1) {
424 result.set_rids(sender.rids);
425 }
426
427 return result;
428}
429
430// Adds SimulcastDescription if indicated by the media description options.
431// MediaContentDescription should already be set up with the send rids.
432static void AddSimulcastToMediaDescription(
433 const MediaDescriptionOptions& media_description_options,
434 MediaContentDescription* description) {
435 RTC_DCHECK(description);
436
437 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800438 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
439 return !params.has_rids();
440 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800441 return;
442 }
443
444 RTC_DCHECK_EQ(1, description->streams().size())
445 << "RIDs are only supported in Unified Plan semantics.";
446 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
447 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
448 description->type() == MediaType::MEDIA_TYPE_VIDEO);
449
450 // One RID or less indicates that simulcast is not needed.
451 if (description->streams()[0].rids().size() <= 1) {
452 return;
453 }
454
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800455 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800456 SimulcastDescription simulcast;
457 simulcast.send_layers() =
458 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800459 description->set_simulcast_description(simulcast);
460}
461
zhihuang1c378ed2017-08-17 14:10:50 -0700462// Adds a StreamParams for each SenderOptions in |sender_options| to
463// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464// |current_params| - All currently known StreamParams of any media type.
465template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700466static bool AddStreamParams(
467 const std::vector<SenderOptions>& sender_options,
468 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800469 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700470 StreamParamsVec* current_streams,
471 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700472 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200473 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700474 return true;
475 }
476
Noah Richards2e7a0982015-05-18 14:02:54 -0700477 const bool include_rtx_streams =
478 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479
brandtr03d5fb12016-11-22 03:37:59 -0800480 const bool include_flexfec_stream =
481 ContainsFlexfecCodec(content_description->codecs());
482
zhihuang1c378ed2017-08-17 14:10:50 -0700483 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 // groupid is empty for StreamParams generated using
485 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700486 StreamParams* param =
487 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000488 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700489 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800490 StreamParams stream_param =
491 sender.rids.empty()
492 ?
493 // Signal SSRCs and legacy simulcast (if requested).
494 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800495 sender, rtcp_cname, include_rtx_streams,
496 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800497 :
498 // Signal RIDs and spec-compliant simulcast (if requested).
499 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
500
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 content_description->AddStream(stream_param);
502
503 // Store the new StreamParams in current_streams.
504 // This is necessary so that we can use the CNAME for other media types.
505 current_streams->push_back(stream_param);
506 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700507 // Use existing generated SSRCs/groups, but update the sync_label if
508 // necessary. This may be needed if a MediaStreamTrack was moved from one
509 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800510 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000511 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 }
513 }
514 return true;
515}
516
517// Updates the transport infos of the |sdesc| according to the given
518// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800519// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
520// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
522 SessionDescription* sdesc) {
523 // The bundle should not be empty.
524 if (!sdesc || !bundle_group.FirstContentName()) {
525 return false;
526 }
527
528 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700529 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 const TransportInfo* selected_transport_info =
531 sdesc->GetTransportInfoByName(selected_content_name);
532 if (!selected_transport_info) {
533 return false;
534 }
535
536 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700537 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700539 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800541 ConnectionRole selected_connection_role =
542 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700543 for (TransportInfo& transport_info : sdesc->transport_infos()) {
544 if (bundle_group.HasContentName(transport_info.content_name) &&
545 transport_info.content_name != selected_content_name) {
546 transport_info.description.ice_ufrag = selected_ufrag;
547 transport_info.description.ice_pwd = selected_pwd;
548 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 }
550 }
551 return true;
552}
553
554// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
555// sets it to |cryptos|.
556static bool GetCryptosByName(const SessionDescription* sdesc,
557 const std::string& content_name,
558 CryptoParamsVec* cryptos) {
559 if (!sdesc || !cryptos) {
560 return false;
561 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800563 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 return false;
565 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800566 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 return true;
568}
569
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
571// which are not available in |filter|.
572static void PruneCryptos(const CryptoParamsVec& filter,
573 CryptoParamsVec* target_cryptos) {
574 if (!target_cryptos) {
575 return;
576 }
tzik21995802018-04-26 17:38:28 +0900577
578 target_cryptos->erase(
579 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
580 // Returns true if the |crypto|'s cipher_suite is not
581 // found in |filter|.
582 [&filter](const CryptoParams& crypto) {
583 for (const CryptoParams& entry : filter) {
584 if (entry.cipher_suite == crypto.cipher_suite)
585 return false;
586 }
587 return true;
588 }),
589 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590}
591
592static bool IsRtpContent(SessionDescription* sdesc,
593 const std::string& content_name) {
594 bool is_rtp = false;
595 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800596 if (content && content->media_description()) {
597 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 }
599 return is_rtp;
600}
601
602// Updates the crypto parameters of the |sdesc| according to the given
603// |bundle_group|. The crypto parameters of all the contents within the
604// |bundle_group| should be updated to use the common subset of the
605// available cryptos.
606static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
607 SessionDescription* sdesc) {
608 // The bundle should not be empty.
609 if (!sdesc || !bundle_group.FirstContentName()) {
610 return false;
611 }
612
wu@webrtc.org78187522013-10-07 23:32:02 +0000613 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 // Get the common cryptos.
615 const ContentNames& content_names = bundle_group.content_names();
616 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700617 bool first = true;
618 for (const std::string& content_name : content_names) {
619 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 continue;
621 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000622 // The common cryptos are needed if any of the content does not have DTLS
623 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700624 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000625 common_cryptos_needed = true;
626 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700627 if (first) {
628 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700630 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 return false;
632 }
633 if (common_cryptos.empty()) {
634 // If there's no crypto params, we should just return.
635 return true;
636 }
637 } else {
638 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700639 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 return false;
641 }
642 PruneCryptos(cryptos, &common_cryptos);
643 }
644 }
645
wu@webrtc.org78187522013-10-07 23:32:02 +0000646 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 return false;
648 }
649
650 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700651 for (const std::string& content_name : content_names) {
652 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 continue;
654 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700655 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800657 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 if (!media_desc) {
659 return false;
660 }
661 media_desc->set_cryptos(common_cryptos);
662 }
663 }
664 return true;
665}
666
Steve Anton5c72e712018-12-10 14:25:30 -0800667static std::vector<const ContentInfo*> GetActiveContents(
668 const SessionDescription& description,
669 const MediaSessionOptions& session_options) {
670 std::vector<const ContentInfo*> active_contents;
671 for (size_t i = 0; i < description.contents().size(); ++i) {
672 RTC_DCHECK_LT(i, session_options.media_description_options.size());
673 const ContentInfo& content = description.contents()[i];
674 const MediaDescriptionOptions& media_options =
675 session_options.media_description_options[i];
676 if (!content.rejected && !media_options.stopped &&
677 content.name == media_options.mid) {
678 active_contents.push_back(&content);
679 }
680 }
681 return active_contents;
682}
683
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684template <class C>
685static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800686 for (const auto& codec : codecs) {
687 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 return true;
689 }
690 }
691 return false;
692}
693
694template <class C>
695static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200696 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697}
698
brandtr03d5fb12016-11-22 03:37:59 -0800699template <class C>
700static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
701 for (const auto& codec : codecs) {
702 if (IsFlexfecCodec(codec)) {
703 return true;
704 }
705 }
706 return false;
707}
708
709template <class C>
710static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200711 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800712}
713
zhihuang1c378ed2017-08-17 14:10:50 -0700714// Create a media content to be offered for the given |sender_options|,
715// according to the given options.rtcp_mux, session_options.is_muc, codecs,
716// secure_transport, crypto, and current_streams. If we don't currently have
717// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
718// created (according to crypto_suites). The created content is added to the
719// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200720static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800721 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700722 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000723 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 const CryptoParamsVec* current_cryptos,
725 const std::vector<std::string>& crypto_suites,
726 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800727 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200729 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700730 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700731 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
732 offer->set_rtcp_reduced_size(true);
733 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 offer->set_rtp_header_extensions(rtp_extensions);
735
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800736 AddSimulcastToMediaDescription(media_description_options, offer);
737
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 if (secure_policy != SEC_DISABLED) {
739 if (current_cryptos) {
740 AddMediaCryptos(*current_cryptos, offer);
741 }
742 if (offer->cryptos().empty()) {
743 if (!CreateMediaCryptos(crypto_suites, offer)) {
744 return false;
745 }
746 }
747 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748
deadbeef7af91dd2016-12-13 11:29:11 -0800749 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 return false;
751 }
752 return true;
753}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200754template <class C>
755static bool CreateMediaContentOffer(
756 const MediaDescriptionOptions& media_description_options,
757 const MediaSessionOptions& session_options,
758 const std::vector<C>& codecs,
759 const SecurePolicy& secure_policy,
760 const CryptoParamsVec* current_cryptos,
761 const std::vector<std::string>& crypto_suites,
762 const RtpHeaderExtensions& rtp_extensions,
763 UniqueRandomIdGenerator* ssrc_generator,
764 StreamParamsVec* current_streams,
765 MediaContentDescriptionImpl<C>* offer) {
766 offer->AddCodecs(codecs);
767 if (!AddStreamParams(media_description_options.sender_options,
768 session_options.rtcp_cname, ssrc_generator,
769 current_streams, offer)) {
770 return false;
771 }
772
773 return CreateContentOffer(media_description_options, session_options,
774 secure_policy, current_cryptos, crypto_suites,
775 rtp_extensions, ssrc_generator, current_streams,
776 offer);
777}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778
779template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000780static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800781 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000782 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800783 const int codec2_id) {
784 const C* codec1 = FindCodecById(codecs1, codec1_id);
785 const C* codec2 = FindCodecById(codecs2, codec2_id);
786 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000787}
788
789template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790static void NegotiateCodecs(const std::vector<C>& local_codecs,
791 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200792 std::vector<C>* negotiated_codecs,
793 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800794 for (const C& ours : local_codecs) {
795 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700796 // Note that we intentionally only find one matching codec for each of our
797 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800798 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
799 C negotiated = ours;
800 negotiated.IntersectFeedbackParams(theirs);
801 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800802 const auto apt_it =
803 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800804 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800805 RTC_DCHECK(apt_it != theirs.params.end());
806 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 }
Niels Möller039743e2018-10-23 10:07:25 +0200808 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800809 webrtc::H264::GenerateProfileLevelIdForAnswer(
810 ours.params, theirs.params, &negotiated.params);
811 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800812 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700813 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800814 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 }
816 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200817 if (keep_offer_order) {
818 // RFC3264: Although the answerer MAY list the formats in their desired
819 // order of preference, it is RECOMMENDED that unless there is a
820 // specific reason, the answerer list formats in the same relative order
821 // they were present in the offer.
822 // This can be skipped when the transceiver has any codec preferences.
823 std::unordered_map<int, int> payload_type_preferences;
824 int preference = static_cast<int>(offered_codecs.size() + 1);
825 for (const C& codec : offered_codecs) {
826 payload_type_preferences[codec.id] = preference--;
827 }
828 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
829 const C& b) {
830 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
831 });
deadbeef67cf2c12016-04-13 10:07:16 -0700832 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833}
834
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800835// Finds a codec in |codecs2| that matches |codec_to_match|, which is
836// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
837// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800839static bool FindMatchingCodec(const std::vector<C>& codecs1,
840 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841 const C& codec_to_match,
842 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700843 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
844 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800845 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
846 return &codec == &codec_to_match;
847 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800848 for (const C& potential_match : codecs2) {
849 if (potential_match.Matches(codec_to_match)) {
850 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800851 int apt_value_1 = 0;
852 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800853 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
854 &apt_value_1) ||
855 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
856 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100857 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800858 continue;
859 }
860 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
861 apt_value_2)) {
862 continue;
863 }
864 }
865 if (found_codec) {
866 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 }
868 return true;
869 }
870 }
871 return false;
872}
873
zhihuang1c378ed2017-08-17 14:10:50 -0700874// Find the codec in |codec_list| that |rtx_codec| is associated with.
875template <class C>
876static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
877 const C& rtx_codec) {
878 std::string associated_pt_str;
879 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
880 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100881 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
882 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700883 return nullptr;
884 }
885
886 int associated_pt;
887 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100888 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
889 << " of RTX codec " << rtx_codec.name
890 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700891 return nullptr;
892 }
893
894 // Find the associated reference codec for the reference RTX codec.
895 const C* associated_codec = FindCodecById(codec_list, associated_pt);
896 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100897 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
898 << associated_pt << " for RTX codec " << rtx_codec.name
899 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700900 }
901 return associated_codec;
902}
903
904// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905// already exist in |offered_codecs| and ensure the payload types don't
906// collide.
907template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700908static void MergeCodecs(const std::vector<C>& reference_codecs,
909 std::vector<C>* offered_codecs,
910 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800912 for (const C& reference_codec : reference_codecs) {
913 if (!IsRtxCodec(reference_codec) &&
914 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
915 reference_codec, nullptr)) {
916 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917 used_pltypes->FindAndSetIdUsed(&codec);
918 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919 }
920 }
921
922 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800923 for (const C& reference_codec : reference_codecs) {
924 if (IsRtxCodec(reference_codec) &&
925 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
926 reference_codec, nullptr)) {
927 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700928 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700929 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700930 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700931 continue;
932 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800933 // Find a codec in the offered list that matches the reference codec.
934 // Its payload type may be different than the reference codec.
935 C matching_codec;
936 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800937 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100938 RTC_LOG(LS_WARNING)
939 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800940 continue;
941 }
942
943 rtx_codec.params[kCodecParamAssociatedPayloadType] =
944 rtc::ToString(matching_codec.id);
945 used_pltypes->FindAndSetIdUsed(&rtx_codec);
946 offered_codecs->push_back(rtx_codec);
947 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 }
949}
950
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200951template <typename Codecs>
952static Codecs MatchCodecPreference(
953 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
954 const Codecs& codecs) {
955 Codecs filtered_codecs;
956 std::set<std::string> kept_codecs_ids;
957 bool want_rtx = false;
958
959 for (const auto& codec_preference : codec_preferences) {
960 auto found_codec = absl::c_find_if(
961 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
962 webrtc::RtpCodecParameters codec_parameters =
963 codec.ToCodecParameters();
964 return codec_parameters.name == codec_preference.name &&
965 codec_parameters.kind == codec_preference.kind &&
966 codec_parameters.num_channels ==
967 codec_preference.num_channels &&
968 codec_parameters.clock_rate == codec_preference.clock_rate &&
969 codec_parameters.parameters == codec_preference.parameters;
970 });
971
972 if (found_codec != codecs.end()) {
973 filtered_codecs.push_back(*found_codec);
974 kept_codecs_ids.insert(std::to_string(found_codec->id));
975 } else if (IsRtxCodec(codec_preference)) {
976 want_rtx = true;
977 }
978 }
979
980 if (want_rtx) {
981 for (const auto& codec : codecs) {
982 if (IsRtxCodec(codec)) {
983 const auto apt =
984 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
985 if (apt != codec.params.end() &&
986 kept_codecs_ids.count(apt->second) > 0) {
987 filtered_codecs.push_back(codec);
988 }
989 }
990 }
991 }
992
993 return filtered_codecs;
994}
995
zhihuang1c378ed2017-08-17 14:10:50 -0700996static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
997 const webrtc::RtpExtension& ext_to_match,
998 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800999 auto it = absl::c_find_if(
1000 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
1001 // We assume that all URIs are given in a canonical
1002 // format.
1003 return extension.uri == ext_to_match.uri &&
1004 extension.encrypt == ext_to_match.encrypt;
1005 });
Steve Anton3a66edf2018-09-10 12:57:37 -07001006 if (it == extensions.end()) {
1007 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001008 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001009 if (found_extension) {
1010 *found_extension = *it;
1011 }
1012 return true;
zhihuang1c378ed2017-08-17 14:10:50 -07001013}
1014
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -07001016 const webrtc::RtpExtension& ext_to_match,
1017 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -07001018 // We assume that all URIs are given in a canonical format.
1019 const webrtc::RtpExtension* found =
1020 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
1021 ext_to_match.uri);
1022 if (!found) {
1023 return false;
1024 }
1025 if (found_extension) {
1026 *found_extension = *found;
1027 }
1028 return true;
1029}
1030
1031static bool FindByUriWithEncryptionPreference(
1032 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001033 const webrtc::RtpExtension& ext_to_match,
1034 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001035 webrtc::RtpExtension* found_extension) {
1036 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001037 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001039 if (extension.uri == ext_to_match.uri) {
1040 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001041 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001042 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001043 }
1044 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001046 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 }
1048 }
jbauch5869f502017-06-29 12:31:36 -07001049 if (unencrypted_extension) {
1050 if (found_extension) {
1051 *found_extension = *unencrypted_extension;
1052 }
1053 return true;
1054 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 return false;
1056}
1057
zhihuang1c378ed2017-08-17 14:10:50 -07001058// Adds all extensions from |reference_extensions| to |offered_extensions| that
1059// don't already exist in |offered_extensions| and ensure the IDs don't
1060// collide. If an extension is added, it's also added to |regular_extensions| or
1061// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1062// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1063// |offered_extensions| is for either audio or video while |regular_extensions|
1064// and |encrypted_extensions| are used for both audio and video. There could be
1065// overlap between audio extensions and video extensions.
1066static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1067 RtpHeaderExtensions* offered_extensions,
1068 RtpHeaderExtensions* regular_extensions,
1069 RtpHeaderExtensions* encrypted_extensions,
1070 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001071 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001072 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1073 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001074 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001075 if (reference_extension.encrypt) {
1076 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1077 &existing)) {
1078 offered_extensions->push_back(existing);
1079 } else {
1080 used_ids->FindAndSetIdUsed(&reference_extension);
1081 encrypted_extensions->push_back(reference_extension);
1082 offered_extensions->push_back(reference_extension);
1083 }
olka3c747662017-08-17 06:50:32 -07001084 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001085 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1086 &existing)) {
1087 offered_extensions->push_back(existing);
1088 } else {
1089 used_ids->FindAndSetIdUsed(&reference_extension);
1090 regular_extensions->push_back(reference_extension);
1091 offered_extensions->push_back(reference_extension);
1092 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001093 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094 }
1095 }
1096}
1097
jbauch5869f502017-06-29 12:31:36 -07001098static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1099 RtpHeaderExtensions* all_extensions,
1100 UsedRtpHeaderExtensionIds* used_ids) {
1101 RtpHeaderExtensions encrypted_extensions;
1102 for (const webrtc::RtpExtension& extension : *extensions) {
1103 webrtc::RtpExtension existing;
1104 // Don't add encrypted extensions again that were already included in a
1105 // previous offer or regular extensions that are also included as encrypted
1106 // extensions.
1107 if (extension.encrypt ||
1108 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1109 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001110 &existing) &&
1111 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001112 continue;
1113 }
1114
1115 if (FindByUri(*all_extensions, extension, &existing)) {
1116 encrypted_extensions.push_back(existing);
1117 } else {
1118 webrtc::RtpExtension encrypted(extension);
1119 encrypted.encrypt = true;
1120 used_ids->FindAndSetIdUsed(&encrypted);
1121 all_extensions->push_back(encrypted);
1122 encrypted_extensions.push_back(encrypted);
1123 }
1124 }
1125 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001126 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001127}
1128
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129static void NegotiateRtpHeaderExtensions(
1130 const RtpHeaderExtensions& local_extensions,
1131 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001132 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001133 RtpHeaderExtensions* negotiated_extensions) {
1134 // TransportSequenceNumberV2 is not offered by default. The special logic for
1135 // the TransportSequenceNumber extensions works as follows:
1136 // Offer Answer
1137 // V1 V1 if in local_extensions.
1138 // V1 and V2 V2 regardless of local_extensions.
1139 // V2 V2 regardless of local_extensions.
1140 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1141 webrtc::RtpExtension::FindHeaderExtensionByUri(
1142 offered_extensions,
1143 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1144
Steve Anton3a66edf2018-09-10 12:57:37 -07001145 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001146 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001147 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001148 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001149 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001150 if (transport_sequence_number_v2_offer &&
1151 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1152 // Don't respond to
1153 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1154 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001155 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001156 continue;
1157 } else {
1158 // We respond with their RTP header extension id.
1159 negotiated_extensions->push_back(theirs);
1160 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001161 }
1162 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001163
1164 if (transport_sequence_number_v2_offer) {
1165 // Respond that we support kTransportSequenceNumberV2Uri.
1166 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1167 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168}
1169
1170static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001171 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1172 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001173 return absl::EqualsIgnoreCase(
1174 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001175 }),
1176 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177}
1178
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001179template <class C>
1180static bool SetCodecsInAnswer(
1181 const MediaContentDescriptionImpl<C>* offer,
1182 const std::vector<C>& local_codecs,
1183 const MediaDescriptionOptions& media_description_options,
1184 const MediaSessionOptions& session_options,
1185 UniqueRandomIdGenerator* ssrc_generator,
1186 StreamParamsVec* current_streams,
1187 MediaContentDescriptionImpl<C>* answer) {
1188 std::vector<C> negotiated_codecs;
1189 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1190 media_description_options.codec_preferences.empty());
1191 answer->AddCodecs(negotiated_codecs);
1192 answer->set_protocol(offer->protocol());
1193 if (!AddStreamParams(media_description_options.sender_options,
1194 session_options.rtcp_cname, ssrc_generator,
1195 current_streams, answer)) {
1196 return false; // Something went seriously wrong.
1197 }
1198 return true;
1199}
1200
zhihuang1c378ed2017-08-17 14:10:50 -07001201// Create a media content to be answered for the given |sender_options|
1202// according to the given session_options.rtcp_mux, session_options.streams,
1203// codecs, crypto, and current_streams. If we don't currently have crypto (in
1204// current_cryptos) and it is enabled (in secure_policy), crypto is created
1205// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1206// negotiated with the offer. If the negotiation fails, this method returns
1207// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001209 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001210 const MediaDescriptionOptions& media_description_options,
1211 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001212 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213 const CryptoParamsVec* current_cryptos,
1214 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001215 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001216 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001219 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001220 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001222 NegotiateRtpHeaderExtensions(
1223 local_rtp_extenstions, offer->rtp_header_extensions(),
1224 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1226
zhihuang1c378ed2017-08-17 14:10:50 -07001227 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001228 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1229 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1230 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231
1232 if (sdes_policy != SEC_DISABLED) {
1233 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001234 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1235 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 if (current_cryptos) {
1237 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1238 }
1239 answer->AddCrypto(crypto);
1240 }
1241 }
1242
deadbeef7af91dd2016-12-13 11:29:11 -08001243 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 return false;
1245 }
1246
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001247 AddSimulcastToMediaDescription(media_description_options, answer);
1248
Steve Anton4e70a722017-11-28 14:57:10 -08001249 answer->set_direction(NegotiateRtpTransceiverDirection(
1250 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 return true;
1252}
1253
1254static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001255 const std::string& protocol,
1256 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001257 // Since not all applications serialize and deserialize the media protocol,
1258 // we will have to accept |protocol| to be empty.
1259 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 return true;
1261 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001262
zhihuangcf5b37c2016-05-05 11:44:35 -07001263 if (type == MEDIA_TYPE_DATA) {
1264 // Check for SCTP, but also for RTP for RTP-based data channels.
1265 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1266 if (secure_transport) {
1267 // Most likely scenarios first.
1268 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1269 IsPlainRtp(protocol);
1270 } else {
1271 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1272 }
1273 }
1274
1275 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1276 // JSEP specifies.
1277 if (secure_transport) {
1278 // Most likely scenarios first.
1279 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1280 } else {
1281 return IsPlainRtp(protocol);
1282 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283}
1284
1285static void SetMediaProtocol(bool secure_transport,
1286 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001287 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001288 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001289 else if (secure_transport)
1290 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001291 else
1292 desc->set_protocol(kMediaProtocolAvpf);
1293}
1294
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001295// Gets the TransportInfo of the given |content_name| from the
1296// |current_description|. If doesn't exist, returns a new one.
1297static const TransportDescription* GetTransportDescription(
1298 const std::string& content_name,
1299 const SessionDescription* current_description) {
1300 const TransportDescription* desc = NULL;
1301 if (current_description) {
1302 const TransportInfo* info =
1303 current_description->GetTransportInfoByName(content_name);
1304 if (info) {
1305 desc = &info->description;
1306 }
1307 }
1308 return desc;
1309}
1310
1311// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001312static bool IsDtlsActive(const ContentInfo* content,
1313 const SessionDescription* current_description) {
1314 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001315 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001316 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001317
zhihuang1c378ed2017-08-17 14:10:50 -07001318 size_t msection_index = content - &current_description->contents()[0];
1319
1320 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001321 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001322 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001323
zhihuang1c378ed2017-08-17 14:10:50 -07001324 return current_description->transport_infos()[msection_index]
1325 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001326}
1327
Steve Anton8ffb9c32017-08-31 15:45:38 -07001328void MediaDescriptionOptions::AddAudioSender(
1329 const std::string& track_id,
1330 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001331 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001332 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001333}
1334
Steve Anton8ffb9c32017-08-31 15:45:38 -07001335void MediaDescriptionOptions::AddVideoSender(
1336 const std::string& track_id,
1337 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001338 const std::vector<RidDescription>& rids,
1339 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001340 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001341 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001342 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1343 << "RIDs are the compliant way to indicate simulcast.";
1344 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1345 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1346 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001347}
1348
zhihuang1c378ed2017-08-17 14:10:50 -07001349void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1350 const std::string& stream_id) {
1351 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001352 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1353 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001354 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001355}
1356
Steve Anton8ffb9c32017-08-31 15:45:38 -07001357void MediaDescriptionOptions::AddSenderInternal(
1358 const std::string& track_id,
1359 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001360 const std::vector<RidDescription>& rids,
1361 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001362 int num_sim_layers) {
1363 // TODO(steveanton): Support any number of stream ids.
1364 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001365 SenderOptions options;
1366 options.track_id = track_id;
1367 options.stream_ids = stream_ids;
1368 options.simulcast_layers = simulcast_layers;
1369 options.rids = rids;
1370 options.num_sim_layers = num_sim_layers;
1371 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001372}
1373
zhihuang1c378ed2017-08-17 14:10:50 -07001374bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001375 return absl::c_any_of(
1376 media_description_options,
1377 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001378}
1379
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001381 const TransportDescriptionFactory* transport_desc_factory,
1382 rtc::UniqueRandomIdGenerator* ssrc_generator)
1383 : ssrc_generator_(ssrc_generator),
1384 transport_desc_factory_(transport_desc_factory) {
1385 RTC_DCHECK(ssrc_generator_);
1386}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001387
1388MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1389 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001390 const TransportDescriptionFactory* transport_desc_factory,
1391 rtc::UniqueRandomIdGenerator* ssrc_generator)
1392 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001393 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1394 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001395 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001396 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001398 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001399 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001400}
1401
ossudedfd282016-06-14 07:12:39 -07001402const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1403 const {
ossu075af922016-06-14 03:29:38 -07001404 return audio_sendrecv_codecs_;
1405}
1406
1407const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1408 return audio_send_codecs_;
1409}
1410
1411const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1412 return audio_recv_codecs_;
1413}
1414
1415void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001416 const AudioCodecs& send_codecs,
1417 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001418 audio_send_codecs_ = send_codecs;
1419 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001420 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001421}
1422
Amit Hilbuch77938e62018-12-21 09:23:38 -08001423static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1424 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001425
1426 rtc::UniqueNumberGenerator<int> unique_id_generator;
1427 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1428 for (const webrtc::RtpExtension& extension : *extensions) {
1429 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1430 RTC_DCHECK(collision_free);
1431 }
1432
Amit Hilbuch77938e62018-12-21 09:23:38 -08001433 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001434 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1435 unique_id_generator()));
1436 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1437 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001438 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001439 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001440}
1441
1442RtpHeaderExtensions
1443MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1444 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1445 if (is_unified_plan_) {
1446 AddUnifiedPlanExtensions(&extensions);
1447 }
1448
1449 return extensions;
1450}
1451
1452RtpHeaderExtensions
1453MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1454 RtpHeaderExtensions extensions = video_rtp_extensions_;
1455 if (is_unified_plan_) {
1456 AddUnifiedPlanExtensions(&extensions);
1457 }
1458
1459 return extensions;
1460}
1461
Steve Anton6fe1fba2018-12-11 10:15:23 -08001462std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001463 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001464 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001465 // Must have options for each existing section.
1466 if (current_description) {
1467 RTC_DCHECK_LE(current_description->contents().size(),
1468 session_options.media_description_options.size());
1469 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001471 IceCredentialsIterator ice_credentials(
1472 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001473
1474 std::vector<const ContentInfo*> current_active_contents;
1475 if (current_description) {
1476 current_active_contents =
1477 GetActiveContents(*current_description, session_options);
1478 }
1479
1480 StreamParamsVec current_streams =
1481 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482
zhihuang1c378ed2017-08-17 14:10:50 -07001483 AudioCodecs offer_audio_codecs;
1484 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001485 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001486 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001487 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001488
zhihuang1c378ed2017-08-17 14:10:50 -07001489 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001491 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001493 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001494 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495
1496 RtpHeaderExtensions audio_rtp_extensions;
1497 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001498 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1499 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500
Steve Anton5c72e712018-12-10 14:25:30 -08001501 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001502
zhihuang1c378ed2017-08-17 14:10:50 -07001503 // Iterate through the media description options, matching with existing media
1504 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001505 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001506 for (const MediaDescriptionOptions& media_description_options :
1507 session_options.media_description_options) {
1508 const ContentInfo* current_content = nullptr;
1509 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001510 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001511 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001512 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001513 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001514 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001515 media_description_options.type));
1516 }
1517 switch (media_description_options.type) {
1518 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001519 if (!AddAudioContentForOffer(
1520 media_description_options, session_options, current_content,
1521 current_description, audio_rtp_extensions, offer_audio_codecs,
1522 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001523 return nullptr;
1524 }
1525 break;
1526 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001527 if (!AddVideoContentForOffer(
1528 media_description_options, session_options, current_content,
1529 current_description, video_rtp_extensions, offer_video_codecs,
1530 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001531 return nullptr;
1532 }
1533 break;
1534 case MEDIA_TYPE_DATA:
1535 if (!AddDataContentForOffer(media_description_options, session_options,
1536 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001537 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001538 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001539 return nullptr;
1540 }
1541 break;
1542 default:
1543 RTC_NOTREACHED();
1544 }
1545 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546 }
1547
1548 // Bundle the contents together, if we've been asked to do so, and update any
1549 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001550 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001551 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001552 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001553 if (content.rejected) {
1554 continue;
1555 }
zhihuang1c378ed2017-08-17 14:10:50 -07001556 // TODO(deadbeef): There are conditions that make bundling two media
1557 // descriptions together illegal. For example, they use the same payload
1558 // type to represent different codecs, or same IDs for different header
1559 // extensions. We need to detect this and not try to bundle those media
1560 // descriptions together.
1561 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001562 }
Steve Anton2bed3972019-01-04 17:04:30 -08001563 if (!offer_bundle.content_names().empty()) {
1564 offer->AddGroup(offer_bundle);
1565 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1566 RTC_LOG(LS_ERROR)
1567 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1568 return nullptr;
1569 }
1570 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1571 RTC_LOG(LS_ERROR)
1572 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1573 return nullptr;
1574 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001575 }
1576 }
Steve Antone831b8c2018-02-01 12:22:16 -08001577
1578 // The following determines how to signal MSIDs to ensure compatibility with
1579 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001580 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001581 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1582 // Plan answerers will look at a=msid and Plan B answerers will look at the
1583 // a=ssrc MSID line.
1584 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1585 cricket::kMsidSignalingSsrcAttribute);
1586 } else {
1587 // Plan B always signals MSID using a=ssrc lines.
1588 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1589 }
1590
Johannes Kron89f874e2018-11-12 10:25:48 +01001591 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1592
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001593 if (session_options.media_transport_settings.has_value()) {
1594 offer->AddMediaTransportSetting(
1595 session_options.media_transport_settings->transport_name,
1596 session_options.media_transport_settings->transport_setting);
1597 }
1598
Steve Anton6fe1fba2018-12-11 10:15:23 -08001599 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600}
1601
Steve Anton6fe1fba2018-12-11 10:15:23 -08001602std::unique_ptr<SessionDescription>
1603MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001604 const SessionDescription* offer,
1605 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001606 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001607 if (!offer) {
1608 return nullptr;
1609 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001610
Steve Anton5c72e712018-12-10 14:25:30 -08001611 // Must have options for exactly as many sections as in the offer.
1612 RTC_DCHECK_EQ(offer->contents().size(),
1613 session_options.media_description_options.size());
1614
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001615 IceCredentialsIterator ice_credentials(
1616 session_options.pooled_ice_credentials);
1617
Steve Anton5c72e712018-12-10 14:25:30 -08001618 std::vector<const ContentInfo*> current_active_contents;
1619 if (current_description) {
1620 current_active_contents =
1621 GetActiveContents(*current_description, session_options);
1622 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623
Steve Anton5c72e712018-12-10 14:25:30 -08001624 StreamParamsVec current_streams =
1625 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001626
zhihuang1c378ed2017-08-17 14:10:50 -07001627 // Get list of all possible codecs that respects existing payload type
1628 // mappings and uses a single payload type space.
1629 //
1630 // Note that these lists may be further filtered for each m= section; this
1631 // step is done just to establish the payload type mappings shared by all
1632 // sections.
1633 AudioCodecs answer_audio_codecs;
1634 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001635 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001636 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001637 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001638
1639 if (!session_options.vad_enabled) {
1640 // If application doesn't want CN codecs in answer.
1641 StripCNCodecs(&answer_audio_codecs);
1642 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001643 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001644 session_options.data_channel_type == DCT_SCTP);
1645
Steve Anton5c72e712018-12-10 14:25:30 -08001646 auto answer = absl::make_unique<SessionDescription>();
1647
1648 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1649 // group in the answer with the appropriate content names.
1650 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1651 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1652 // Transport info shared by the bundle group.
1653 std::unique_ptr<TransportInfo> bundle_transport;
1654
1655 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1656
zhihuang1c378ed2017-08-17 14:10:50 -07001657 // Iterate through the media description options, matching with existing
1658 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001659 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001660 for (const MediaDescriptionOptions& media_description_options :
1661 session_options.media_description_options) {
1662 const ContentInfo* offer_content = &offer->contents()[msection_index];
1663 // Media types and MIDs must match between the remote offer and the
1664 // MediaDescriptionOptions.
1665 RTC_DCHECK(
1666 IsMediaContentOfType(offer_content, media_description_options.type));
1667 RTC_DCHECK(media_description_options.mid == offer_content->name);
1668 const ContentInfo* current_content = nullptr;
1669 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001670 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001671 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001672 }
zhihuang1c378ed2017-08-17 14:10:50 -07001673 switch (media_description_options.type) {
1674 case MEDIA_TYPE_AUDIO:
1675 if (!AddAudioContentForAnswer(
1676 media_description_options, session_options, offer_content,
1677 offer, current_content, current_description,
1678 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001679 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001680 return nullptr;
1681 }
1682 break;
1683 case MEDIA_TYPE_VIDEO:
1684 if (!AddVideoContentForAnswer(
1685 media_description_options, session_options, offer_content,
1686 offer, current_content, current_description,
1687 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001688 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001689 return nullptr;
1690 }
1691 break;
1692 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001693 if (!AddDataContentForAnswer(
1694 media_description_options, session_options, offer_content,
1695 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001696 bundle_transport.get(), answer_rtp_data_codecs,
1697 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001698 return nullptr;
1699 }
1700 break;
1701 default:
1702 RTC_NOTREACHED();
1703 }
1704 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001705 // See if we can add the newly generated m= section to the BUNDLE group in
1706 // the answer.
1707 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001708 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001709 offer_bundle->HasContentName(added.name)) {
1710 answer_bundle.AddContentName(added.name);
1711 bundle_transport.reset(
1712 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001714 }
1715
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001716 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1717 // it's empty. RFC5888 says:
1718 //
1719 // A SIP entity that receives an offer that contains an "a=group" line
1720 // with semantics that are understood MUST return an answer that
1721 // contains an "a=group" line with the same semantics.
1722 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001723 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001724 }
deadbeefb7892532017-02-22 19:35:18 -08001725
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001726 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001727 // Share the same ICE credentials and crypto params across all contents,
1728 // as BUNDLE requires.
1729 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001730 RTC_LOG(LS_ERROR)
1731 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001732 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001733 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001734
deadbeefb7892532017-02-22 19:35:18 -08001735 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001736 RTC_LOG(LS_ERROR)
1737 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001738 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001739 }
1740 }
1741
Steve Antone831b8c2018-02-01 12:22:16 -08001742 // The following determines how to signal MSIDs to ensure compatibility with
1743 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001744 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001745 // Unified Plan needs to look at what the offer included to find the most
1746 // compatible answer.
1747 if (offer->msid_signaling() == 0) {
1748 // We end up here in one of three cases:
1749 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1750 // matter what we pick here.
1751 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1752 // it also doesn't matter what we pick here.
1753 // 3. Media that's either sendonly or inactive from the remote endpoint.
1754 // We don't have any information to say whether the endpoint is Plan B
1755 // or Unified Plan, so be conservative and send both.
1756 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1757 cricket::kMsidSignalingSsrcAttribute);
1758 } else if (offer->msid_signaling() ==
1759 (cricket::kMsidSignalingMediaSection |
1760 cricket::kMsidSignalingSsrcAttribute)) {
1761 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1762 // probably talking to a Unified Plan endpoint so respond with just
1763 // a=msid.
1764 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1765 } else {
1766 // Otherwise, it's clear which method the offerer is using so repeat that
1767 // back to them.
1768 answer->set_msid_signaling(offer->msid_signaling());
1769 }
1770 } else {
1771 // Plan B always signals MSID using a=ssrc lines.
1772 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1773 }
1774
Steve Anton6fe1fba2018-12-11 10:15:23 -08001775 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001776}
1777
ossu075af922016-06-14 03:29:38 -07001778const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1779 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001780 switch (direction) {
1781 // If stream is inactive - generate list as if sendrecv.
1782 case RtpTransceiverDirection::kSendRecv:
1783 case RtpTransceiverDirection::kInactive:
1784 return audio_sendrecv_codecs_;
1785 case RtpTransceiverDirection::kSendOnly:
1786 return audio_send_codecs_;
1787 case RtpTransceiverDirection::kRecvOnly:
1788 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001789 }
Steve Anton1d03a752017-11-27 14:30:09 -08001790 RTC_NOTREACHED();
1791 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001792}
1793
1794const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1795 const RtpTransceiverDirection& offer,
1796 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001797 switch (answer) {
1798 // For inactive and sendrecv answers, generate lists as if we were to accept
1799 // the offer's direction. See RFC 3264 Section 6.1.
1800 case RtpTransceiverDirection::kSendRecv:
1801 case RtpTransceiverDirection::kInactive:
1802 return GetAudioCodecsForOffer(
1803 webrtc::RtpTransceiverDirectionReversed(offer));
1804 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001805 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001806 case RtpTransceiverDirection::kRecvOnly:
1807 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001808 }
Steve Anton1d03a752017-11-27 14:30:09 -08001809 RTC_NOTREACHED();
1810 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001811}
1812
Steve Anton5c72e712018-12-10 14:25:30 -08001813void MergeCodecsFromDescription(
1814 const std::vector<const ContentInfo*>& current_active_contents,
1815 AudioCodecs* audio_codecs,
1816 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001817 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001818 UsedPayloadTypes* used_pltypes) {
1819 for (const ContentInfo* content : current_active_contents) {
1820 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001821 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001822 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001823 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001824 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001825 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001826 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001827 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001828 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001829 const RtpDataContentDescription* data =
1830 content->media_description()->as_rtp_data();
1831 if (data) {
1832 // Only relevant for RTP datachannels
1833 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1834 used_pltypes);
1835 }
zhihuang1c378ed2017-08-17 14:10:50 -07001836 }
1837 }
1838}
1839
1840// Getting codecs for an offer involves these steps:
1841//
1842// 1. Construct payload type -> codec mappings for current description.
1843// 2. Add any reference codecs that weren't already present
1844// 3. For each individual media description (m= section), filter codecs based
1845// on the directional attribute (happens in another method).
1846void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001847 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 AudioCodecs* audio_codecs,
1849 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001850 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001852 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1853 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001854 UsedPayloadTypes used_pltypes;
1855 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001856 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001857
Steve Anton5c72e712018-12-10 14:25:30 -08001858 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001859 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1860 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001861 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001862}
1863
1864// Getting codecs for an answer involves these steps:
1865//
1866// 1. Construct payload type -> codec mappings for current description.
1867// 2. Add any codecs from the offer that weren't already present.
1868// 3. Add any remaining codecs that weren't already present.
1869// 4. For each individual media description (m= section), filter codecs based
1870// on the directional attribute (happens in another method).
1871void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001872 const std::vector<const ContentInfo*>& current_active_contents,
1873 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001874 AudioCodecs* audio_codecs,
1875 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001876 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001877 // First - get all codecs from the current description if the media type
1878 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1879 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001880 UsedPayloadTypes used_pltypes;
1881 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001882 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001883
1884 // Second - filter out codecs that we don't support at all and should ignore.
1885 AudioCodecs filtered_offered_audio_codecs;
1886 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001887 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001888 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001889 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1890 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001891 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001892 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1893 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1894 filtered_offered_audio_codecs,
1895 offered_audio_codec, nullptr) &&
1896 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1897 offered_audio_codec, nullptr)) {
1898 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1899 }
1900 }
1901 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1902 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001903 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001904 for (const VideoCodec& offered_video_codec : video->codecs()) {
1905 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1906 filtered_offered_video_codecs,
1907 offered_video_codec, nullptr) &&
1908 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1909 offered_video_codec, nullptr)) {
1910 filtered_offered_video_codecs.push_back(offered_video_codec);
1911 }
1912 }
1913 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001914 const RtpDataContentDescription* data =
1915 content.media_description()->as_rtp_data();
1916 if (data) {
1917 // RTP data. This part is inactive for SCTP data.
1918 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1919 if (!FindMatchingCodec<RtpDataCodec>(
1920 data->codecs(), filtered_offered_rtp_data_codecs,
1921 offered_rtp_data_codec, nullptr) &&
1922 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1923 offered_rtp_data_codec,
1924 nullptr)) {
1925 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1926 }
zhihuang1c378ed2017-08-17 14:10:50 -07001927 }
1928 }
1929 }
1930 }
1931
Steve Anton5c72e712018-12-10 14:25:30 -08001932 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001933 // |remote_offer|.
1934 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1935 &used_pltypes);
1936 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1937 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001938 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001939 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940}
1941
1942void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001943 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001944 RtpHeaderExtensions* offer_audio_extensions,
1945 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001946 // All header extensions allocated from the same range to avoid potential
1947 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001949 RtpHeaderExtensions all_regular_extensions;
1950 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951
1952 // First - get all extensions from the current description if the media type
1953 // is used.
1954 // Add them to |used_ids| so the local ids are not reused if a new media
1955 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001956 for (const ContentInfo* content : current_active_contents) {
1957 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1958 const AudioContentDescription* audio =
1959 content->media_description()->as_audio();
1960 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1961 &all_regular_extensions, &all_encrypted_extensions,
1962 &used_ids);
1963 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1964 const VideoContentDescription* video =
1965 content->media_description()->as_video();
1966 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1967 &all_regular_extensions, &all_encrypted_extensions,
1968 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969 }
1970 }
1971
Steve Anton5c72e712018-12-10 14:25:30 -08001972 // Add our default RTP header extensions that are not in the current
1973 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001974 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1975 &all_regular_extensions, &all_encrypted_extensions,
1976 &used_ids);
1977 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1978 &all_regular_extensions, &all_encrypted_extensions,
1979 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001980
jbauch5869f502017-06-29 12:31:36 -07001981 // TODO(jbauch): Support adding encrypted header extensions to existing
1982 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001983 if (enable_encrypted_rtp_header_extensions_ &&
1984 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001985 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1986 &all_encrypted_extensions, &used_ids);
1987 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1988 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001989 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990}
1991
1992bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001993 const std::string& content_name,
1994 const TransportOptions& transport_options,
1995 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001996 SessionDescription* offer_desc,
1997 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001998 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001999 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002000 const TransportDescription* current_tdesc =
2001 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08002002 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002003 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
2004 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08002005 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002006 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
2007 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 }
Steve Anton06817cd2018-12-18 15:55:30 -08002009 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
2010 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011}
2012
Steve Anton1a9d3c32018-12-10 17:18:54 -08002013std::unique_ptr<TransportDescription>
2014MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002015 const std::string& content_name,
2016 const SessionDescription* offer_desc,
2017 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002018 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002019 bool require_transport_attributes,
2020 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021 if (!transport_desc_factory_)
2022 return NULL;
2023 const TransportDescription* offer_tdesc =
2024 GetTransportDescription(content_name, offer_desc);
2025 const TransportDescription* current_tdesc =
2026 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08002027 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
2028 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002029 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030}
2031
2032bool MediaSessionDescriptionFactory::AddTransportAnswer(
2033 const std::string& content_name,
2034 const TransportDescription& transport_desc,
2035 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08002036 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037 return true;
2038}
2039
zhihuang1c378ed2017-08-17 14:10:50 -07002040// |audio_codecs| = set of all possible codecs that can be used, with correct
2041// payload type mappings
2042//
2043// |supported_audio_codecs| = set of codecs that are supported for the direction
2044// of this m= section
2045//
2046// acd->codecs() = set of previously negotiated codecs for this m= section
2047//
2048// The payload types should come from audio_codecs, but the order should come
2049// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2050// change existing codec priority, and that new codecs are added with the right
2051// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002053 const MediaDescriptionOptions& media_description_options,
2054 const MediaSessionOptions& session_options,
2055 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002056 const SessionDescription* current_description,
2057 const RtpHeaderExtensions& audio_rtp_extensions,
2058 const AudioCodecs& audio_codecs,
2059 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002060 SessionDescription* desc,
2061 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002062 // Filter audio_codecs (which includes all codecs, with correctly remapped
2063 // payload types) based on transceiver direction.
2064 const AudioCodecs& supported_audio_codecs =
2065 GetAudioCodecsForOffer(media_description_options.direction);
2066
2067 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002068
2069 if (!media_description_options.codec_preferences.empty()) {
2070 // Add the codecs from the current transceiver's codec preferences.
2071 // They override any existing codecs from previous negotiations.
2072 filtered_codecs = MatchCodecPreference(
2073 media_description_options.codec_preferences, supported_audio_codecs);
2074 } else {
2075 // Add the codecs from current content if it exists and is not rejected nor
2076 // recycled.
2077 if (current_content && !current_content->rejected &&
2078 current_content->name == media_description_options.mid) {
2079 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2080 const AudioContentDescription* acd =
2081 current_content->media_description()->as_audio();
2082 for (const AudioCodec& codec : acd->codecs()) {
2083 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2084 nullptr)) {
2085 filtered_codecs.push_back(codec);
2086 }
zhihuang1c378ed2017-08-17 14:10:50 -07002087 }
2088 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002089 // Add other supported audio codecs.
2090 AudioCodec found_codec;
2091 for (const AudioCodec& codec : supported_audio_codecs) {
2092 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2093 codec, &found_codec) &&
2094 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2095 filtered_codecs, codec, nullptr)) {
2096 // Use the |found_codec| from |audio_codecs| because it has the
2097 // correctly mapped payload type.
2098 filtered_codecs.push_back(found_codec);
2099 }
zhihuang1c378ed2017-08-17 14:10:50 -07002100 }
2101 }
deadbeef44f08192015-12-15 16:20:09 -08002102
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002103 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002104 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2105 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002106
kwiberg31022942016-03-11 14:18:21 -08002107 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002108 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002109 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2110 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002111 if (!CreateMediaContentOffer(media_description_options, session_options,
2112 filtered_codecs, sdes_policy,
2113 GetCryptos(current_content), crypto_suites,
2114 audio_rtp_extensions, ssrc_generator_,
2115 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002116 return false;
2117 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002118
2119 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2120 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002121
Steve Anton4e70a722017-11-28 14:57:10 -08002122 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002123
Steve Anton5adfafd2017-12-20 16:34:00 -08002124 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002125 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002126 if (!AddTransportOffer(media_description_options.mid,
2127 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002128 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002129 return false;
2130 }
2131
2132 return true;
2133}
2134
2135bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002136 const MediaDescriptionOptions& media_description_options,
2137 const MediaSessionOptions& session_options,
2138 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002139 const SessionDescription* current_description,
2140 const RtpHeaderExtensions& video_rtp_extensions,
2141 const VideoCodecs& video_codecs,
2142 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002143 SessionDescription* desc,
2144 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002145 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002146 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2147 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002148
kwiberg31022942016-03-11 14:18:21 -08002149 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002150 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002151 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2152 &crypto_suites);
2153
2154 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002155
2156 if (!media_description_options.codec_preferences.empty()) {
2157 // Add the codecs from the current transceiver's codec preferences.
2158 // They override any existing codecs from previous negotiations.
2159 filtered_codecs = MatchCodecPreference(
2160 media_description_options.codec_preferences, video_codecs_);
2161 } else {
2162 // Add the codecs from current content if it exists and is not rejected nor
2163 // recycled.
2164 if (current_content && !current_content->rejected &&
2165 current_content->name == media_description_options.mid) {
2166 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2167 const VideoContentDescription* vcd =
2168 current_content->media_description()->as_video();
2169 for (const VideoCodec& codec : vcd->codecs()) {
2170 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2171 nullptr)) {
2172 filtered_codecs.push_back(codec);
2173 }
zhihuang1c378ed2017-08-17 14:10:50 -07002174 }
2175 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002176 // Add other supported video codecs.
2177 VideoCodec found_codec;
2178 for (const VideoCodec& codec : video_codecs_) {
2179 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2180 &found_codec) &&
2181 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2182 nullptr)) {
2183 // Use the |found_codec| from |video_codecs| because it has the
2184 // correctly mapped payload type.
2185 filtered_codecs.push_back(found_codec);
2186 }
zhihuang1c378ed2017-08-17 14:10:50 -07002187 }
2188 }
2189
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002190 if (!CreateMediaContentOffer(media_description_options, session_options,
2191 filtered_codecs, sdes_policy,
2192 GetCryptos(current_content), crypto_suites,
2193 video_rtp_extensions, ssrc_generator_,
2194 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002195 return false;
2196 }
2197
zhihuang1c378ed2017-08-17 14:10:50 -07002198 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002199
2200 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2201 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002202
Steve Anton4e70a722017-11-28 14:57:10 -08002203 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002204
Steve Anton5adfafd2017-12-20 16:34:00 -08002205 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002206 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002207 if (!AddTransportOffer(media_description_options.mid,
2208 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002209 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002210 return false;
2211 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002212 return true;
2213}
2214
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002215bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2216 const MediaDescriptionOptions& media_description_options,
2217 const MediaSessionOptions& session_options,
2218 const ContentInfo* current_content,
2219 const SessionDescription* current_description,
2220 StreamParamsVec* current_streams,
2221 SessionDescription* desc,
2222 IceCredentialsIterator* ice_credentials) const {
2223 std::unique_ptr<SctpDataContentDescription> data(
2224 new SctpDataContentDescription());
2225
2226 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2227
2228 cricket::SecurePolicy sdes_policy =
2229 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2230 : secure();
2231 std::vector<std::string> crypto_suites;
2232 // SDES doesn't make sense for SCTP, so we disable it, and we only
2233 // get SDES crypto suites for RTP-based data channels.
2234 sdes_policy = cricket::SEC_DISABLED;
2235 // Unlike SetMediaProtocol below, we need to set the protocol
2236 // before we call CreateMediaContentOffer. Otherwise,
2237 // CreateMediaContentOffer won't know this is SCTP and will
2238 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002239 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002240 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002241 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002242 data->set_max_message_size(kSctpSendBufferSize);
2243
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002244 if (!CreateContentOffer(media_description_options, session_options,
2245 sdes_policy, GetCryptos(current_content),
2246 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2247 current_streams, data.get())) {
2248 return false;
2249 }
2250
2251 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002252 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002253 if (!AddTransportOffer(media_description_options.mid,
2254 media_description_options.transport_options,
2255 current_description, desc, ice_credentials)) {
2256 return false;
2257 }
2258 return true;
2259}
2260
2261bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2262 const MediaDescriptionOptions& media_description_options,
2263 const MediaSessionOptions& session_options,
2264 const ContentInfo* current_content,
2265 const SessionDescription* current_description,
2266 const RtpDataCodecs& rtp_data_codecs,
2267 StreamParamsVec* current_streams,
2268 SessionDescription* desc,
2269 IceCredentialsIterator* ice_credentials) const {
2270 std::unique_ptr<RtpDataContentDescription> data(
2271 new RtpDataContentDescription());
2272 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2273
2274 cricket::SecurePolicy sdes_policy =
2275 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2276 : secure();
2277 std::vector<std::string> crypto_suites;
2278 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2279 &crypto_suites);
2280 if (!CreateMediaContentOffer(media_description_options, session_options,
2281 rtp_data_codecs, sdes_policy,
2282 GetCryptos(current_content), crypto_suites,
2283 RtpHeaderExtensions(), ssrc_generator_,
2284 current_streams, data.get())) {
2285 return false;
2286 }
2287
2288 data->set_bandwidth(kDataMaxBandwidth);
2289 SetMediaProtocol(secure_transport, data.get());
2290 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002291 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002292 if (!AddTransportOffer(media_description_options.mid,
2293 media_description_options.transport_options,
2294 current_description, desc, ice_credentials)) {
2295 return false;
2296 }
2297 return true;
2298}
2299
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002300bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002301 const MediaDescriptionOptions& media_description_options,
2302 const MediaSessionOptions& session_options,
2303 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002304 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002305 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002307 SessionDescription* desc,
2308 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002309 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2310 // If the DataChannel type is not specified, use the DataChannel type in
2311 // the current description.
2312 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002313 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002314 is_sctp = (current_content->media_description()->protocol() ==
2315 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002316 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002317 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002318 return AddSctpDataContentForOffer(
2319 media_description_options, session_options, current_content,
2320 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002321 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002322 return AddRtpDataContentForOffer(media_description_options, session_options,
2323 current_content, current_description,
2324 rtp_data_codecs, current_streams, desc,
2325 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002326 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002327}
2328
zhihuang1c378ed2017-08-17 14:10:50 -07002329// |audio_codecs| = set of all possible codecs that can be used, with correct
2330// payload type mappings
2331//
2332// |supported_audio_codecs| = set of codecs that are supported for the direction
2333// of this m= section
2334//
2335// acd->codecs() = set of previously negotiated codecs for this m= section
2336//
2337// The payload types should come from audio_codecs, but the order should come
2338// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2339// change existing codec priority, and that new codecs are added with the right
2340// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002341bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002342 const MediaDescriptionOptions& media_description_options,
2343 const MediaSessionOptions& session_options,
2344 const ContentInfo* offer_content,
2345 const SessionDescription* offer_description,
2346 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002347 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002348 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002349 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002350 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002351 SessionDescription* answer,
2352 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002353 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002354 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002355 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002356
Steve Anton1a9d3c32018-12-10 17:18:54 -08002357 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002358 media_description_options.mid, offer_description,
2359 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002360 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002361 if (!audio_transport) {
2362 return false;
2363 }
2364
zhihuang1c378ed2017-08-17 14:10:50 -07002365 // Pick codecs based on the requested communications direction in the offer
2366 // and the selected direction in the answer.
2367 // Note these will be filtered one final time in CreateMediaContentAnswer.
2368 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002369 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002370 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002371 AudioCodecs supported_audio_codecs =
2372 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2373
2374 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002375
2376 if (!media_description_options.codec_preferences.empty()) {
2377 filtered_codecs = MatchCodecPreference(
2378 media_description_options.codec_preferences, supported_audio_codecs);
2379 } else {
2380 // Add the codecs from current content if it exists and is not rejected nor
2381 // recycled.
2382 if (current_content && !current_content->rejected &&
2383 current_content->name == media_description_options.mid) {
2384 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2385 const AudioContentDescription* acd =
2386 current_content->media_description()->as_audio();
2387 for (const AudioCodec& codec : acd->codecs()) {
2388 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2389 nullptr)) {
2390 filtered_codecs.push_back(codec);
2391 }
zhihuang1c378ed2017-08-17 14:10:50 -07002392 }
2393 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002394 // Add other supported audio codecs.
2395 for (const AudioCodec& codec : supported_audio_codecs) {
2396 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2397 codec, nullptr) &&
2398 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2399 filtered_codecs, codec, nullptr)) {
2400 // We should use the local codec with local parameters and the codec id
2401 // would be correctly mapped in |NegotiateCodecs|.
2402 filtered_codecs.push_back(codec);
2403 }
zhihuang1c378ed2017-08-17 14:10:50 -07002404 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002405 }
2406
zhihuang1c378ed2017-08-17 14:10:50 -07002407 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2408 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002409 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002410 new AudioContentDescription());
2411 // Do not require or create SDES cryptos if DTLS is used.
2412 cricket::SecurePolicy sdes_policy =
2413 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002414 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2415 media_description_options, session_options,
2416 ssrc_generator_, current_streams,
2417 audio_answer.get())) {
2418 return false;
2419 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002420 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002421 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002422 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002423 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002424 enable_encrypted_rtp_header_extensions_, current_streams,
2425 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002426 return false; // Fails the session setup.
2427 }
2428
deadbeefb7892532017-02-22 19:35:18 -08002429 bool secure = bundle_transport ? bundle_transport->description.secure()
2430 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002431 bool rejected = media_description_options.stopped ||
2432 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002433 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2434 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002435 if (!AddTransportAnswer(media_description_options.mid,
2436 *(audio_transport.get()), answer)) {
2437 return false;
2438 }
2439
2440 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002441 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2442 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002443 }
2444
zhihuang1c378ed2017-08-17 14:10:50 -07002445 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002446 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002447 return true;
2448}
2449
2450bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002451 const MediaDescriptionOptions& media_description_options,
2452 const MediaSessionOptions& session_options,
2453 const ContentInfo* offer_content,
2454 const SessionDescription* offer_description,
2455 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002456 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002457 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002458 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002459 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002460 SessionDescription* answer,
2461 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002462 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002463 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002464 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002465
Steve Anton1a9d3c32018-12-10 17:18:54 -08002466 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002467 media_description_options.mid, offer_description,
2468 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002469 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002470 if (!video_transport) {
2471 return false;
2472 }
2473
zhihuang1c378ed2017-08-17 14:10:50 -07002474 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002475
2476 if (!media_description_options.codec_preferences.empty()) {
2477 filtered_codecs = MatchCodecPreference(
2478 media_description_options.codec_preferences, video_codecs_);
2479 } else {
2480 // Add the codecs from current content if it exists and is not rejected nor
2481 // recycled.
2482 if (current_content && !current_content->rejected &&
2483 current_content->name == media_description_options.mid) {
2484 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2485 const VideoContentDescription* vcd =
2486 current_content->media_description()->as_video();
2487 for (const VideoCodec& codec : vcd->codecs()) {
2488 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2489 nullptr)) {
2490 filtered_codecs.push_back(codec);
2491 }
zhihuang1c378ed2017-08-17 14:10:50 -07002492 }
2493 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002494 // Add other supported video codecs.
2495 for (const VideoCodec& codec : video_codecs_) {
2496 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2497 nullptr) &&
2498 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2499 nullptr)) {
2500 // We should use the local codec with local parameters and the codec id
2501 // would be correctly mapped in |NegotiateCodecs|.
2502 filtered_codecs.push_back(codec);
2503 }
zhihuang1c378ed2017-08-17 14:10:50 -07002504 }
2505 }
2506
2507 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2508 session_options.bundle_enabled;
2509
kwiberg31022942016-03-11 14:18:21 -08002510 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002511 new VideoContentDescription());
2512 // Do not require or create SDES cryptos if DTLS is used.
2513 cricket::SecurePolicy sdes_policy =
2514 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002515 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2516 media_description_options, session_options,
2517 ssrc_generator_, current_streams,
2518 video_answer.get())) {
2519 return false;
2520 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002521 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002522 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002523 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002524 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002525 enable_encrypted_rtp_header_extensions_, current_streams,
2526 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002527 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002528 }
deadbeefb7892532017-02-22 19:35:18 -08002529 bool secure = bundle_transport ? bundle_transport->description.secure()
2530 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002531 bool rejected = media_description_options.stopped ||
2532 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002533 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2534 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002535 if (!AddTransportAnswer(media_description_options.mid,
2536 *(video_transport.get()), answer)) {
2537 return false;
2538 }
2539
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002540 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002541 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002542 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002543 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2544 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002545 }
zhihuang1c378ed2017-08-17 14:10:50 -07002546 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002547 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002548 return true;
2549}
2550
2551bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002552 const MediaDescriptionOptions& media_description_options,
2553 const MediaSessionOptions& session_options,
2554 const ContentInfo* offer_content,
2555 const SessionDescription* offer_description,
2556 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002557 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002558 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002559 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002560 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002561 SessionDescription* answer,
2562 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002563 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002564 media_description_options.mid, offer_description,
2565 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002566 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002567 if (!data_transport) {
2568 return false;
2569 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002570
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002571 // Do not require or create SDES cryptos if DTLS is used.
2572 cricket::SecurePolicy sdes_policy =
2573 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002574 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2575 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002576 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002577 std::unique_ptr<MediaContentDescription> data_answer;
2578 if (offer_content->media_description()->as_sctp()) {
2579 // SCTP data content
2580 data_answer = absl::make_unique<SctpDataContentDescription>();
2581 const SctpDataContentDescription* offer_data_description =
2582 offer_content->media_description()->as_sctp();
2583 // Respond with the offerer's proto, whatever it is.
2584 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002585 // Respond with our max message size or the remote max messsage size,
2586 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002587 // 0 is treated specially - it means "I can accept any size". Since
2588 // we do not implement infinite size messages, reply with
2589 // kSctpSendBufferSize.
2590 if (offer_data_description->max_message_size() == 0) {
2591 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2592 } else {
2593 data_answer->as_sctp()->set_max_message_size(std::min(
2594 offer_data_description->max_message_size(), kSctpSendBufferSize));
2595 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002596 if (!CreateMediaContentAnswer(
2597 offer_data_description, media_description_options, session_options,
2598 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2599 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2600 current_streams, bundle_enabled, data_answer.get())) {
2601 return false; // Fails the session setup.
2602 }
2603 // Respond with sctpmap if the offer uses sctpmap.
2604 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2605 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2606 } else {
2607 // RTP offer
2608 data_answer = absl::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002609
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002610 const RtpDataContentDescription* offer_data_description =
2611 offer_content->media_description()->as_rtp_data();
2612 RTC_CHECK(offer_data_description);
2613 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2614 media_description_options, session_options,
2615 ssrc_generator_, current_streams,
2616 data_answer->as_rtp_data())) {
2617 return false;
2618 }
2619 if (!CreateMediaContentAnswer(
2620 offer_data_description, media_description_options, session_options,
2621 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2622 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2623 current_streams, bundle_enabled, data_answer.get())) {
2624 return false; // Fails the session setup.
2625 }
2626 }
Steve Anton46afbf92019-05-10 11:15:18 -07002627
deadbeefb7892532017-02-22 19:35:18 -08002628 bool secure = bundle_transport ? bundle_transport->description.secure()
2629 : data_transport->secure();
2630
zhihuang1c378ed2017-08-17 14:10:50 -07002631 bool rejected = session_options.data_channel_type == DCT_NONE ||
2632 media_description_options.stopped ||
2633 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002634 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2635 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002636 if (!AddTransportAnswer(media_description_options.mid,
2637 *(data_transport.get()), answer)) {
2638 return false;
2639 }
2640
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002641 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002642 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002643 } else {
2644 // RFC 3264
2645 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002646 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002647 }
zhihuang1c378ed2017-08-17 14:10:50 -07002648 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002649 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002650 return true;
2651}
2652
zhihuang1c378ed2017-08-17 14:10:50 -07002653void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2654 audio_sendrecv_codecs_.clear();
2655 all_audio_codecs_.clear();
2656 // Compute the audio codecs union.
2657 for (const AudioCodec& send : audio_send_codecs_) {
2658 all_audio_codecs_.push_back(send);
2659 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2660 send, nullptr)) {
2661 // It doesn't make sense to have an RTX codec we support sending but not
2662 // receiving.
2663 RTC_DCHECK(!IsRtxCodec(send));
2664 }
2665 }
2666 for (const AudioCodec& recv : audio_recv_codecs_) {
2667 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2668 recv, nullptr)) {
2669 all_audio_codecs_.push_back(recv);
2670 }
2671 }
2672 // Use NegotiateCodecs to merge our codec lists, since the operation is
2673 // essentially the same. Put send_codecs as the offered_codecs, which is the
2674 // order we'd like to follow. The reasoning is that encoding is usually more
2675 // expensive than decoding, and prioritizing a codec in the send list probably
2676 // means it's a codec we can handle efficiently.
2677 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002678 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002679}
2680
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002682 return (content && (content->type == MediaProtocolType::kRtp ||
2683 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684}
2685
2686bool IsAudioContent(const ContentInfo* content) {
2687 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2688}
2689
2690bool IsVideoContent(const ContentInfo* content) {
2691 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2692}
2693
2694bool IsDataContent(const ContentInfo* content) {
2695 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2696}
2697
deadbeef0ed85b22016-02-23 17:24:52 -08002698const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2699 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002700 for (const ContentInfo& content : contents) {
2701 if (IsMediaContentOfType(&content, media_type)) {
2702 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703 }
2704 }
deadbeef0ed85b22016-02-23 17:24:52 -08002705 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706}
2707
2708const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2709 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2710}
2711
2712const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2713 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2714}
2715
2716const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2717 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2718}
2719
Steve Antonad7bffc2018-01-22 10:21:56 -08002720const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2721 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002722 if (sdesc == nullptr) {
2723 return nullptr;
2724 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002725
2726 return GetFirstMediaContent(sdesc->contents(), media_type);
2727}
2728
2729const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2730 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2731}
2732
2733const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2734 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2735}
2736
2737const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2738 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2739}
2740
2741const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002742 const SessionDescription* sdesc,
2743 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002745 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746}
2747
2748const AudioContentDescription* GetFirstAudioContentDescription(
2749 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002750 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2751 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752}
2753
2754const VideoContentDescription* GetFirstVideoContentDescription(
2755 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002756 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2757 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758}
2759
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002760const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2761 const SessionDescription* sdesc) {
2762 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2763 return desc ? desc->as_rtp_data() : nullptr;
2764}
2765
2766const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2767 const SessionDescription* sdesc) {
2768 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2769 return desc ? desc->as_sctp() : nullptr;
2770}
2771
2772// Returns a shim representing either an SctpDataContentDescription
2773// or an RtpDataContentDescription, as appropriate.
2774// TODO(bugs.webrtc.org/10597): Remove together with shim.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002775const DataContentDescription* GetFirstDataContentDescription(
2776 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002777 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2778 return desc ? desc->as_data() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779}
2780
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002781//
2782// Non-const versions of the above functions.
2783//
2784
Steve Anton36b29d12017-10-30 09:57:42 -07002785ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002786 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002787 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002788 if (IsMediaContentOfType(&content, media_type)) {
2789 return &content;
2790 }
2791 }
2792 return nullptr;
2793}
2794
Steve Anton36b29d12017-10-30 09:57:42 -07002795ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002796 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2797}
2798
Steve Anton36b29d12017-10-30 09:57:42 -07002799ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002800 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2801}
2802
Steve Anton36b29d12017-10-30 09:57:42 -07002803ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002804 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2805}
2806
Steve Antonad7bffc2018-01-22 10:21:56 -08002807ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2808 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002809 if (sdesc == nullptr) {
2810 return nullptr;
2811 }
2812
Steve Anton36b29d12017-10-30 09:57:42 -07002813 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002814}
2815
2816ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2817 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2818}
2819
2820ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2821 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2822}
2823
2824ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2825 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2826}
2827
2828MediaContentDescription* GetFirstMediaContentDescription(
2829 SessionDescription* sdesc,
2830 MediaType media_type) {
2831 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002832 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002833}
2834
2835AudioContentDescription* GetFirstAudioContentDescription(
2836 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002837 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2838 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002839}
2840
2841VideoContentDescription* GetFirstVideoContentDescription(
2842 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002843 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2844 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002845}
2846
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002847RtpDataContentDescription* GetFirstRtpDataContentDescription(
2848 SessionDescription* sdesc) {
2849 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2850 return desc ? desc->as_rtp_data() : nullptr;
2851}
2852
2853SctpDataContentDescription* GetFirstSctpDataContentDescription(
2854 SessionDescription* sdesc) {
2855 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2856 return desc ? desc->as_sctp() : nullptr;
2857}
2858
2859// Returns shim
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002860DataContentDescription* GetFirstDataContentDescription(
2861 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002862 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2863 return desc ? desc->as_data() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002864}
2865
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866} // namespace cricket