blob: 69ebb841e6d7aa74387fe7d60ad08eda4adc8273 [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"
28#include "p2p/base/p2p_constants.h"
29#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020030#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "pc/rtp_media_utils.h"
32#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "rtc_base/checks.h"
34#include "rtc_base/helpers.h"
35#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020036#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080037#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
39namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080040
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080041using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080042using webrtc::RtpTransceiverDirection;
43
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080045
Benjamin Wrighta54daf12018-10-11 15:33:17 -070046void GetSupportedSdesCryptoSuiteNames(
47 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
48 const webrtc::CryptoOptions& crypto_options,
49 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080050 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070051 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080052 for (const auto crypto : crypto_suites) {
53 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
54 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080055}
Elad Alon157540a2019-02-08 23:37:52 +010056
terelius8c011e52016-04-26 05:28:11 -070057} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058
59namespace cricket {
60
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061// RTP Profile names
62// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
63// RFC4585
64const char kMediaProtocolAvpf[] = "RTP/AVPF";
65// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000066const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
67
deadbeeff3938292015-07-15 12:20:53 -070068// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
69// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070const char kMediaProtocolSavpf[] = "RTP/SAVPF";
71
deadbeef8b7e9ad2017-05-25 09:38:55 -070072// Note that the below functions support some protocol strings purely for
73// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
74// and Interoperability.
75
76static bool IsDtlsRtp(const std::string& protocol) {
77 // Most-likely values first.
78 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
79 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
80}
81
82static bool IsPlainRtp(const std::string& protocol) {
83 // Most-likely values first.
84 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
85 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
86}
87
Steve Anton1d03a752017-11-27 14:30:09 -080088static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
89 RtpTransceiverDirection offer,
90 RtpTransceiverDirection wants) {
91 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
92 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
93 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
94 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
95 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
96 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070097}
98
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099static bool IsMediaContentOfType(const ContentInfo* content,
100 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800101 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 return false;
103 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800104 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105}
106
Yves Gerey665174f2018-06-19 15:03:05 +0200107static bool CreateCryptoParams(int tag,
108 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700109 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700110 int key_len;
111 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200112 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
113 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114 return false;
115 }
jbauchcb560652016-08-04 05:20:32 -0700116
117 int master_key_len = key_len + salt_len;
118 std::string master_key;
119 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
120 return false;
121 }
122
kwiberg352444f2016-11-28 15:58:53 -0800123 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700124 std::string key = rtc::Base64::Encode(master_key);
125
Steve Anton3a66edf2018-09-10 12:57:37 -0700126 crypto_out->tag = tag;
127 crypto_out->cipher_suite = cipher;
128 crypto_out->key_params = kInline;
129 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 return true;
131}
132
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700134 CryptoParamsVec* cryptos_out) {
135 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Steve Anton3a66edf2018-09-10 12:57:37 -0700137 cryptos_out->resize(size + 1);
138 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139}
140
141void AddMediaCryptos(const CryptoParamsVec& cryptos,
142 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700143 for (const CryptoParams& crypto : cryptos) {
144 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145 }
146}
147
148bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
149 MediaContentDescription* media) {
150 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700151 for (const std::string& crypto_suite : crypto_suites) {
152 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153 return false;
154 }
155 }
156 AddMediaCryptos(cryptos, media);
157 return true;
158}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159
zhihuang1c378ed2017-08-17 14:10:50 -0700160const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800161 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700162 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800164 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165}
166
167bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
168 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700169 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800170 auto it = absl::c_find_if(
171 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700172 if (it == cryptos.end()) {
173 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700175 *crypto_out = *it;
176 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177}
178
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700179// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
180// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700181void GetSupportedAudioSdesCryptoSuites(
182 const webrtc::CryptoOptions& crypto_options,
183 std::vector<int>* crypto_suites) {
184 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700185 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
187 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700188 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700189 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
190 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800191 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192}
193
deadbeef7914b8c2017-04-21 03:23:33 -0700194void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700195 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800196 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700197 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
198 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199}
200
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700201void GetSupportedVideoSdesCryptoSuites(
202 const webrtc::CryptoOptions& crypto_options,
203 std::vector<int>* crypto_suites) {
204 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700205 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
206 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
207 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800208 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209}
210
deadbeef7914b8c2017-04-21 03:23:33 -0700211void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700212 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800213 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700214 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
215 crypto_options, crypto_suite_names);
216}
217
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700218void GetSupportedDataSdesCryptoSuites(
219 const webrtc::CryptoOptions& crypto_options,
220 std::vector<int>* crypto_suites) {
221 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700222 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
224 }
225 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
226}
227
228void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700229 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700230 std::vector<std::string>* crypto_suite_names) {
231 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
232 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800233}
234
jbauchcb560652016-08-04 05:20:32 -0700235// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700236// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
237// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700238// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000239static bool SelectCrypto(const MediaContentDescription* offer,
240 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700241 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700242 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
244 const CryptoParamsVec& cryptos = offer->cryptos();
245
Steve Anton3a66edf2018-09-10 12:57:37 -0700246 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700247 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700248 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
249 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
250 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700251 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700252 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253 }
254 }
255 return false;
256}
257
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800259static StreamParamsVec GetCurrentStreamParams(
260 const std::vector<const ContentInfo*>& active_local_contents) {
261 StreamParamsVec stream_params;
262 for (const ContentInfo* content : active_local_contents) {
263 for (const StreamParams& params : content->media_description()->streams()) {
264 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 }
266 }
Steve Anton5c72e712018-12-10 14:25:30 -0800267 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268}
269
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000270// Filters the data codecs for the data channel type.
271void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
272 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700273 const char* codec_name =
274 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700275 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
276 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200277 return absl::EqualsIgnoreCase(codec.name,
278 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700279 }),
280 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000281}
282
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283template <typename IdStruct>
284class UsedIds {
285 public:
286 UsedIds(int min_allowed_id, int max_allowed_id)
287 : min_allowed_id_(min_allowed_id),
288 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200289 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290
291 // Loops through all Id in |ids| and changes its id if it is
292 // already in use by another IdStruct. Call this methods with all Id
293 // in a session description to make sure no duplicate ids exists.
294 // Note that typename Id must be a type of IdStruct.
295 template <typename Id>
296 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700297 for (const Id& id : *ids) {
298 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 }
300 }
301
302 // Finds and sets an unused id if the |idstruct| id is already in use.
303 void FindAndSetIdUsed(IdStruct* idstruct) {
304 const int original_id = idstruct->id;
305 int new_id = idstruct->id;
306
307 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
308 // If the original id is not in range - this is an id that can't be
309 // dynamically changed.
310 return;
311 }
312
313 if (IsIdUsed(original_id)) {
314 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100315 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
316 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317 idstruct->id = new_id;
318 }
319 SetIdUsed(new_id);
320 }
321
322 private:
323 // Returns the first unused id in reverse order.
324 // This hopefully reduce the risk of more collisions. We want to change the
325 // default ids as little as possible.
326 int FindUnusedId() {
327 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
328 --next_id_;
329 }
nisseede5da42017-01-12 05:15:36 -0800330 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 return next_id_;
332 }
333
Yves Gerey665174f2018-06-19 15:03:05 +0200334 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335
Yves Gerey665174f2018-06-19 15:03:05 +0200336 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000337
338 const int min_allowed_id_;
339 const int max_allowed_id_;
340 int next_id_;
341 std::set<int> id_set_;
342};
343
344// Helper class used for finding duplicate RTP payload types among audio, video
345// and data codecs. When bundle is used the payload types may not collide.
346class UsedPayloadTypes : public UsedIds<Codec> {
347 public:
348 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200349 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350
351 private:
352 static const int kDynamicPayloadTypeMin = 96;
353 static const int kDynamicPayloadTypeMax = 127;
354};
355
356// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200357// audio and video extensions. Only applies to one-byte header extensions at the
358// moment. ids > 14 will always be reported as available.
359// TODO(kron): This class needs to be refactored when we start to send two-byte
360// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700361class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 public:
363 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200364 : UsedIds<webrtc::RtpExtension>(
365 webrtc::RtpExtension::kMinId,
366 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367
368 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369};
370
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800371static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
372 const SenderOptions& sender,
373 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800374 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800375 bool include_flexfec_stream,
376 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800377 StreamParams result;
378 result.id = sender.track_id;
379
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800380 // TODO(brandtr): Update when we support multistream protection.
381 if (include_flexfec_stream && sender.num_sim_layers > 1) {
382 include_flexfec_stream = false;
383 RTC_LOG(LS_WARNING)
384 << "Our FlexFEC implementation only supports protecting "
385 "a single media streams. This session has multiple "
386 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800387 }
388
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800389 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
390 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800391
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800392 result.cname = rtcp_cname;
393 result.set_stream_ids(sender.stream_ids);
394
395 return result;
396}
397
398static bool ValidateSimulcastLayers(
399 const std::vector<RidDescription>& rids,
400 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800401 return absl::c_all_of(
402 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
403 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
404 return rid.rid == layer.rid;
405 });
406 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800407}
408
409static StreamParams CreateStreamParamsForNewSenderWithRids(
410 const SenderOptions& sender,
411 const std::string& rtcp_cname) {
412 RTC_DCHECK(!sender.rids.empty());
413 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
414 << "RIDs are the compliant way to indicate simulcast.";
415 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
416 StreamParams result;
417 result.id = sender.track_id;
418 result.cname = rtcp_cname;
419 result.set_stream_ids(sender.stream_ids);
420
421 // More than one rid should be signaled.
422 if (sender.rids.size() > 1) {
423 result.set_rids(sender.rids);
424 }
425
426 return result;
427}
428
429// Adds SimulcastDescription if indicated by the media description options.
430// MediaContentDescription should already be set up with the send rids.
431static void AddSimulcastToMediaDescription(
432 const MediaDescriptionOptions& media_description_options,
433 MediaContentDescription* description) {
434 RTC_DCHECK(description);
435
436 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800437 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
438 return !params.has_rids();
439 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800440 return;
441 }
442
443 RTC_DCHECK_EQ(1, description->streams().size())
444 << "RIDs are only supported in Unified Plan semantics.";
445 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
446 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
447 description->type() == MediaType::MEDIA_TYPE_VIDEO);
448
449 // One RID or less indicates that simulcast is not needed.
450 if (description->streams()[0].rids().size() <= 1) {
451 return;
452 }
453
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800454 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800455 SimulcastDescription simulcast;
456 simulcast.send_layers() =
457 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800458 description->set_simulcast_description(simulcast);
459}
460
zhihuang1c378ed2017-08-17 14:10:50 -0700461// Adds a StreamParams for each SenderOptions in |sender_options| to
462// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463// |current_params| - All currently known StreamParams of any media type.
464template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700465static bool AddStreamParams(
466 const std::vector<SenderOptions>& sender_options,
467 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800468 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700469 StreamParamsVec* current_streams,
470 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700471 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200472 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700473 return true;
474 }
475
Noah Richards2e7a0982015-05-18 14:02:54 -0700476 const bool include_rtx_streams =
477 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478
brandtr03d5fb12016-11-22 03:37:59 -0800479 const bool include_flexfec_stream =
480 ContainsFlexfecCodec(content_description->codecs());
481
zhihuang1c378ed2017-08-17 14:10:50 -0700482 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 // groupid is empty for StreamParams generated using
484 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700485 StreamParams* param =
486 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000487 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700488 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800489 StreamParams stream_param =
490 sender.rids.empty()
491 ?
492 // Signal SSRCs and legacy simulcast (if requested).
493 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800494 sender, rtcp_cname, include_rtx_streams,
495 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800496 :
497 // Signal RIDs and spec-compliant simulcast (if requested).
498 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
499
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 content_description->AddStream(stream_param);
501
502 // Store the new StreamParams in current_streams.
503 // This is necessary so that we can use the CNAME for other media types.
504 current_streams->push_back(stream_param);
505 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700506 // Use existing generated SSRCs/groups, but update the sync_label if
507 // necessary. This may be needed if a MediaStreamTrack was moved from one
508 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800509 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000510 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 }
512 }
513 return true;
514}
515
516// Updates the transport infos of the |sdesc| according to the given
517// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800518// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
519// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
521 SessionDescription* sdesc) {
522 // The bundle should not be empty.
523 if (!sdesc || !bundle_group.FirstContentName()) {
524 return false;
525 }
526
527 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700528 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 const TransportInfo* selected_transport_info =
530 sdesc->GetTransportInfoByName(selected_content_name);
531 if (!selected_transport_info) {
532 return false;
533 }
534
535 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700536 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700538 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800540 ConnectionRole selected_connection_role =
541 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700542 for (TransportInfo& transport_info : sdesc->transport_infos()) {
543 if (bundle_group.HasContentName(transport_info.content_name) &&
544 transport_info.content_name != selected_content_name) {
545 transport_info.description.ice_ufrag = selected_ufrag;
546 transport_info.description.ice_pwd = selected_pwd;
547 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 }
549 }
550 return true;
551}
552
553// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
554// sets it to |cryptos|.
555static bool GetCryptosByName(const SessionDescription* sdesc,
556 const std::string& content_name,
557 CryptoParamsVec* cryptos) {
558 if (!sdesc || !cryptos) {
559 return false;
560 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800562 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 return false;
564 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800565 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 return true;
567}
568
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
570// which are not available in |filter|.
571static void PruneCryptos(const CryptoParamsVec& filter,
572 CryptoParamsVec* target_cryptos) {
573 if (!target_cryptos) {
574 return;
575 }
tzik21995802018-04-26 17:38:28 +0900576
577 target_cryptos->erase(
578 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
579 // Returns true if the |crypto|'s cipher_suite is not
580 // found in |filter|.
581 [&filter](const CryptoParams& crypto) {
582 for (const CryptoParams& entry : filter) {
583 if (entry.cipher_suite == crypto.cipher_suite)
584 return false;
585 }
586 return true;
587 }),
588 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589}
590
591static bool IsRtpContent(SessionDescription* sdesc,
592 const std::string& content_name) {
593 bool is_rtp = false;
594 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800595 if (content && content->media_description()) {
596 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 }
598 return is_rtp;
599}
600
601// Updates the crypto parameters of the |sdesc| according to the given
602// |bundle_group|. The crypto parameters of all the contents within the
603// |bundle_group| should be updated to use the common subset of the
604// available cryptos.
605static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
606 SessionDescription* sdesc) {
607 // The bundle should not be empty.
608 if (!sdesc || !bundle_group.FirstContentName()) {
609 return false;
610 }
611
wu@webrtc.org78187522013-10-07 23:32:02 +0000612 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 // Get the common cryptos.
614 const ContentNames& content_names = bundle_group.content_names();
615 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700616 bool first = true;
617 for (const std::string& content_name : content_names) {
618 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 continue;
620 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000621 // The common cryptos are needed if any of the content does not have DTLS
622 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700623 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000624 common_cryptos_needed = true;
625 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700626 if (first) {
627 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700629 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 return false;
631 }
632 if (common_cryptos.empty()) {
633 // If there's no crypto params, we should just return.
634 return true;
635 }
636 } else {
637 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700638 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 return false;
640 }
641 PruneCryptos(cryptos, &common_cryptos);
642 }
643 }
644
wu@webrtc.org78187522013-10-07 23:32:02 +0000645 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 return false;
647 }
648
649 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700650 for (const std::string& content_name : content_names) {
651 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 continue;
653 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700654 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800656 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 if (!media_desc) {
658 return false;
659 }
660 media_desc->set_cryptos(common_cryptos);
661 }
662 }
663 return true;
664}
665
Steve Anton5c72e712018-12-10 14:25:30 -0800666static std::vector<const ContentInfo*> GetActiveContents(
667 const SessionDescription& description,
668 const MediaSessionOptions& session_options) {
669 std::vector<const ContentInfo*> active_contents;
670 for (size_t i = 0; i < description.contents().size(); ++i) {
671 RTC_DCHECK_LT(i, session_options.media_description_options.size());
672 const ContentInfo& content = description.contents()[i];
673 const MediaDescriptionOptions& media_options =
674 session_options.media_description_options[i];
675 if (!content.rejected && !media_options.stopped &&
676 content.name == media_options.mid) {
677 active_contents.push_back(&content);
678 }
679 }
680 return active_contents;
681}
682
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683template <class C>
684static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800685 for (const auto& codec : codecs) {
686 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 return true;
688 }
689 }
690 return false;
691}
692
693template <class C>
694static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200695 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696}
697
brandtr03d5fb12016-11-22 03:37:59 -0800698template <class C>
699static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
700 for (const auto& codec : codecs) {
701 if (IsFlexfecCodec(codec)) {
702 return true;
703 }
704 }
705 return false;
706}
707
708template <class C>
709static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200710 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800711}
712
zhihuang1c378ed2017-08-17 14:10:50 -0700713// Create a media content to be offered for the given |sender_options|,
714// according to the given options.rtcp_mux, session_options.is_muc, codecs,
715// secure_transport, crypto, and current_streams. If we don't currently have
716// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
717// created (according to crypto_suites). The created content is added to the
718// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200719static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800720 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700721 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000722 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 const CryptoParamsVec* current_cryptos,
724 const std::vector<std::string>& crypto_suites,
725 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800726 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200728 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700729 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700730 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
731 offer->set_rtcp_reduced_size(true);
732 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 offer->set_rtp_header_extensions(rtp_extensions);
734
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800735 AddSimulcastToMediaDescription(media_description_options, offer);
736
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 if (secure_policy != SEC_DISABLED) {
738 if (current_cryptos) {
739 AddMediaCryptos(*current_cryptos, offer);
740 }
741 if (offer->cryptos().empty()) {
742 if (!CreateMediaCryptos(crypto_suites, offer)) {
743 return false;
744 }
745 }
746 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747
deadbeef7af91dd2016-12-13 11:29:11 -0800748 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 return false;
750 }
751 return true;
752}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200753template <class C>
754static bool CreateMediaContentOffer(
755 const MediaDescriptionOptions& media_description_options,
756 const MediaSessionOptions& session_options,
757 const std::vector<C>& codecs,
758 const SecurePolicy& secure_policy,
759 const CryptoParamsVec* current_cryptos,
760 const std::vector<std::string>& crypto_suites,
761 const RtpHeaderExtensions& rtp_extensions,
762 UniqueRandomIdGenerator* ssrc_generator,
763 StreamParamsVec* current_streams,
764 MediaContentDescriptionImpl<C>* offer) {
765 offer->AddCodecs(codecs);
766 if (!AddStreamParams(media_description_options.sender_options,
767 session_options.rtcp_cname, ssrc_generator,
768 current_streams, offer)) {
769 return false;
770 }
771
772 return CreateContentOffer(media_description_options, session_options,
773 secure_policy, current_cryptos, crypto_suites,
774 rtp_extensions, ssrc_generator, current_streams,
775 offer);
776}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777
778template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000779static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800780 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000781 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800782 const int codec2_id) {
783 const C* codec1 = FindCodecById(codecs1, codec1_id);
784 const C* codec2 = FindCodecById(codecs2, codec2_id);
785 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000786}
787
788template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789static void NegotiateCodecs(const std::vector<C>& local_codecs,
790 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200791 std::vector<C>* negotiated_codecs,
792 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800793 for (const C& ours : local_codecs) {
794 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700795 // Note that we intentionally only find one matching codec for each of our
796 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800797 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
798 C negotiated = ours;
799 negotiated.IntersectFeedbackParams(theirs);
800 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800801 const auto apt_it =
802 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800803 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800804 RTC_DCHECK(apt_it != theirs.params.end());
805 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 }
Niels Möller039743e2018-10-23 10:07:25 +0200807 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800808 webrtc::H264::GenerateProfileLevelIdForAnswer(
809 ours.params, theirs.params, &negotiated.params);
810 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800811 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700812 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800813 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 }
815 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200816 if (keep_offer_order) {
817 // RFC3264: Although the answerer MAY list the formats in their desired
818 // order of preference, it is RECOMMENDED that unless there is a
819 // specific reason, the answerer list formats in the same relative order
820 // they were present in the offer.
821 // This can be skipped when the transceiver has any codec preferences.
822 std::unordered_map<int, int> payload_type_preferences;
823 int preference = static_cast<int>(offered_codecs.size() + 1);
824 for (const C& codec : offered_codecs) {
825 payload_type_preferences[codec.id] = preference--;
826 }
827 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
828 const C& b) {
829 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
830 });
deadbeef67cf2c12016-04-13 10:07:16 -0700831 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832}
833
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800834// Finds a codec in |codecs2| that matches |codec_to_match|, which is
835// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
836// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800838static bool FindMatchingCodec(const std::vector<C>& codecs1,
839 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 const C& codec_to_match,
841 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700842 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
843 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800844 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
845 return &codec == &codec_to_match;
846 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800847 for (const C& potential_match : codecs2) {
848 if (potential_match.Matches(codec_to_match)) {
849 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800850 int apt_value_1 = 0;
851 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
853 &apt_value_1) ||
854 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
855 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100856 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800857 continue;
858 }
859 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
860 apt_value_2)) {
861 continue;
862 }
863 }
864 if (found_codec) {
865 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 }
867 return true;
868 }
869 }
870 return false;
871}
872
zhihuang1c378ed2017-08-17 14:10:50 -0700873// Find the codec in |codec_list| that |rtx_codec| is associated with.
874template <class C>
875static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
876 const C& rtx_codec) {
877 std::string associated_pt_str;
878 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
879 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100880 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
881 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700882 return nullptr;
883 }
884
885 int associated_pt;
886 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100887 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
888 << " of RTX codec " << rtx_codec.name
889 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700890 return nullptr;
891 }
892
893 // Find the associated reference codec for the reference RTX codec.
894 const C* associated_codec = FindCodecById(codec_list, associated_pt);
895 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100896 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
897 << associated_pt << " for RTX codec " << rtx_codec.name
898 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700899 }
900 return associated_codec;
901}
902
903// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904// already exist in |offered_codecs| and ensure the payload types don't
905// collide.
906template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700907static void MergeCodecs(const std::vector<C>& reference_codecs,
908 std::vector<C>* offered_codecs,
909 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800911 for (const C& reference_codec : reference_codecs) {
912 if (!IsRtxCodec(reference_codec) &&
913 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
914 reference_codec, nullptr)) {
915 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 used_pltypes->FindAndSetIdUsed(&codec);
917 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 }
919 }
920
921 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800922 for (const C& reference_codec : reference_codecs) {
923 if (IsRtxCodec(reference_codec) &&
924 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
925 reference_codec, nullptr)) {
926 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700927 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700928 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700929 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700930 continue;
931 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800932 // Find a codec in the offered list that matches the reference codec.
933 // Its payload type may be different than the reference codec.
934 C matching_codec;
935 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800936 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100937 RTC_LOG(LS_WARNING)
938 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800939 continue;
940 }
941
942 rtx_codec.params[kCodecParamAssociatedPayloadType] =
943 rtc::ToString(matching_codec.id);
944 used_pltypes->FindAndSetIdUsed(&rtx_codec);
945 offered_codecs->push_back(rtx_codec);
946 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 }
948}
949
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200950template <typename Codecs>
951static Codecs MatchCodecPreference(
952 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
953 const Codecs& codecs) {
954 Codecs filtered_codecs;
955 std::set<std::string> kept_codecs_ids;
956 bool want_rtx = false;
957
958 for (const auto& codec_preference : codec_preferences) {
959 auto found_codec = absl::c_find_if(
960 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
961 webrtc::RtpCodecParameters codec_parameters =
962 codec.ToCodecParameters();
963 return codec_parameters.name == codec_preference.name &&
964 codec_parameters.kind == codec_preference.kind &&
965 codec_parameters.num_channels ==
966 codec_preference.num_channels &&
967 codec_parameters.clock_rate == codec_preference.clock_rate &&
968 codec_parameters.parameters == codec_preference.parameters;
969 });
970
971 if (found_codec != codecs.end()) {
972 filtered_codecs.push_back(*found_codec);
973 kept_codecs_ids.insert(std::to_string(found_codec->id));
974 } else if (IsRtxCodec(codec_preference)) {
975 want_rtx = true;
976 }
977 }
978
979 if (want_rtx) {
980 for (const auto& codec : codecs) {
981 if (IsRtxCodec(codec)) {
982 const auto apt =
983 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
984 if (apt != codec.params.end() &&
985 kept_codecs_ids.count(apt->second) > 0) {
986 filtered_codecs.push_back(codec);
987 }
988 }
989 }
990 }
991
992 return filtered_codecs;
993}
994
zhihuang1c378ed2017-08-17 14:10:50 -0700995static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
996 const webrtc::RtpExtension& ext_to_match,
997 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800998 auto it = absl::c_find_if(
999 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
1000 // We assume that all URIs are given in a canonical
1001 // format.
1002 return extension.uri == ext_to_match.uri &&
1003 extension.encrypt == ext_to_match.encrypt;
1004 });
Steve Anton3a66edf2018-09-10 12:57:37 -07001005 if (it == extensions.end()) {
1006 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001007 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001008 if (found_extension) {
1009 *found_extension = *it;
1010 }
1011 return true;
zhihuang1c378ed2017-08-17 14:10:50 -07001012}
1013
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -07001015 const webrtc::RtpExtension& ext_to_match,
1016 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -07001017 // We assume that all URIs are given in a canonical format.
1018 const webrtc::RtpExtension* found =
1019 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
1020 ext_to_match.uri);
1021 if (!found) {
1022 return false;
1023 }
1024 if (found_extension) {
1025 *found_extension = *found;
1026 }
1027 return true;
1028}
1029
1030static bool FindByUriWithEncryptionPreference(
1031 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001032 const webrtc::RtpExtension& ext_to_match,
1033 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001034 webrtc::RtpExtension* found_extension) {
1035 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001036 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001038 if (extension.uri == ext_to_match.uri) {
1039 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001040 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001041 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001042 }
1043 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001045 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046 }
1047 }
jbauch5869f502017-06-29 12:31:36 -07001048 if (unencrypted_extension) {
1049 if (found_extension) {
1050 *found_extension = *unencrypted_extension;
1051 }
1052 return true;
1053 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001054 return false;
1055}
1056
zhihuang1c378ed2017-08-17 14:10:50 -07001057// Adds all extensions from |reference_extensions| to |offered_extensions| that
1058// don't already exist in |offered_extensions| and ensure the IDs don't
1059// collide. If an extension is added, it's also added to |regular_extensions| or
1060// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1061// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1062// |offered_extensions| is for either audio or video while |regular_extensions|
1063// and |encrypted_extensions| are used for both audio and video. There could be
1064// overlap between audio extensions and video extensions.
1065static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1066 RtpHeaderExtensions* offered_extensions,
1067 RtpHeaderExtensions* regular_extensions,
1068 RtpHeaderExtensions* encrypted_extensions,
1069 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001070 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001071 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1072 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001073 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001074 if (reference_extension.encrypt) {
1075 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1076 &existing)) {
1077 offered_extensions->push_back(existing);
1078 } else {
1079 used_ids->FindAndSetIdUsed(&reference_extension);
1080 encrypted_extensions->push_back(reference_extension);
1081 offered_extensions->push_back(reference_extension);
1082 }
olka3c747662017-08-17 06:50:32 -07001083 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001084 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1085 &existing)) {
1086 offered_extensions->push_back(existing);
1087 } else {
1088 used_ids->FindAndSetIdUsed(&reference_extension);
1089 regular_extensions->push_back(reference_extension);
1090 offered_extensions->push_back(reference_extension);
1091 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001092 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 }
1094 }
1095}
1096
jbauch5869f502017-06-29 12:31:36 -07001097static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1098 RtpHeaderExtensions* all_extensions,
1099 UsedRtpHeaderExtensionIds* used_ids) {
1100 RtpHeaderExtensions encrypted_extensions;
1101 for (const webrtc::RtpExtension& extension : *extensions) {
1102 webrtc::RtpExtension existing;
1103 // Don't add encrypted extensions again that were already included in a
1104 // previous offer or regular extensions that are also included as encrypted
1105 // extensions.
1106 if (extension.encrypt ||
1107 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1108 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001109 &existing) &&
1110 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001111 continue;
1112 }
1113
1114 if (FindByUri(*all_extensions, extension, &existing)) {
1115 encrypted_extensions.push_back(existing);
1116 } else {
1117 webrtc::RtpExtension encrypted(extension);
1118 encrypted.encrypt = true;
1119 used_ids->FindAndSetIdUsed(&encrypted);
1120 all_extensions->push_back(encrypted);
1121 encrypted_extensions.push_back(encrypted);
1122 }
1123 }
1124 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001125 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001126}
1127
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128static void NegotiateRtpHeaderExtensions(
1129 const RtpHeaderExtensions& local_extensions,
1130 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001131 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001132 RtpHeaderExtensions* negotiated_extensions) {
1133 // TransportSequenceNumberV2 is not offered by default. The special logic for
1134 // the TransportSequenceNumber extensions works as follows:
1135 // Offer Answer
1136 // V1 V1 if in local_extensions.
1137 // V1 and V2 V2 regardless of local_extensions.
1138 // V2 V2 regardless of local_extensions.
1139 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1140 webrtc::RtpExtension::FindHeaderExtensionByUri(
1141 offered_extensions,
1142 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1143
Steve Anton3a66edf2018-09-10 12:57:37 -07001144 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001145 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001146 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001147 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001148 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001149 if (transport_sequence_number_v2_offer &&
1150 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1151 // Don't respond to
1152 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1153 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001154 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001155 continue;
1156 } else {
1157 // We respond with their RTP header extension id.
1158 negotiated_extensions->push_back(theirs);
1159 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160 }
1161 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001162
1163 if (transport_sequence_number_v2_offer) {
1164 // Respond that we support kTransportSequenceNumberV2Uri.
1165 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1166 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167}
1168
1169static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001170 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1171 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001172 return absl::EqualsIgnoreCase(
1173 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001174 }),
1175 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176}
1177
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001178template <class C>
1179static bool SetCodecsInAnswer(
1180 const MediaContentDescriptionImpl<C>* offer,
1181 const std::vector<C>& local_codecs,
1182 const MediaDescriptionOptions& media_description_options,
1183 const MediaSessionOptions& session_options,
1184 UniqueRandomIdGenerator* ssrc_generator,
1185 StreamParamsVec* current_streams,
1186 MediaContentDescriptionImpl<C>* answer) {
1187 std::vector<C> negotiated_codecs;
1188 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1189 media_description_options.codec_preferences.empty());
1190 answer->AddCodecs(negotiated_codecs);
1191 answer->set_protocol(offer->protocol());
1192 if (!AddStreamParams(media_description_options.sender_options,
1193 session_options.rtcp_cname, ssrc_generator,
1194 current_streams, answer)) {
1195 return false; // Something went seriously wrong.
1196 }
1197 return true;
1198}
1199
zhihuang1c378ed2017-08-17 14:10:50 -07001200// Create a media content to be answered for the given |sender_options|
1201// according to the given session_options.rtcp_mux, session_options.streams,
1202// codecs, crypto, and current_streams. If we don't currently have crypto (in
1203// current_cryptos) and it is enabled (in secure_policy), crypto is created
1204// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1205// negotiated with the offer. If the negotiation fails, this method returns
1206// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001208 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001209 const MediaDescriptionOptions& media_description_options,
1210 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001211 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 const CryptoParamsVec* current_cryptos,
1213 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001214 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001215 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001216 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001218 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001219 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001220 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001221 NegotiateRtpHeaderExtensions(
1222 local_rtp_extenstions, offer->rtp_header_extensions(),
1223 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1225
zhihuang1c378ed2017-08-17 14:10:50 -07001226 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001227 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1228 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1229 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230
1231 if (sdes_policy != SEC_DISABLED) {
1232 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001233 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1234 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 if (current_cryptos) {
1236 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1237 }
1238 answer->AddCrypto(crypto);
1239 }
1240 }
1241
deadbeef7af91dd2016-12-13 11:29:11 -08001242 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 return false;
1244 }
1245
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001246 AddSimulcastToMediaDescription(media_description_options, answer);
1247
Steve Anton4e70a722017-11-28 14:57:10 -08001248 answer->set_direction(NegotiateRtpTransceiverDirection(
1249 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 return true;
1251}
1252
1253static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001254 const std::string& protocol,
1255 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001256 // Since not all applications serialize and deserialize the media protocol,
1257 // we will have to accept |protocol| to be empty.
1258 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 return true;
1260 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001261
zhihuangcf5b37c2016-05-05 11:44:35 -07001262 if (type == MEDIA_TYPE_DATA) {
1263 // Check for SCTP, but also for RTP for RTP-based data channels.
1264 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1265 if (secure_transport) {
1266 // Most likely scenarios first.
1267 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1268 IsPlainRtp(protocol);
1269 } else {
1270 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1271 }
1272 }
1273
1274 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1275 // JSEP specifies.
1276 if (secure_transport) {
1277 // Most likely scenarios first.
1278 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1279 } else {
1280 return IsPlainRtp(protocol);
1281 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282}
1283
1284static void SetMediaProtocol(bool secure_transport,
1285 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001286 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001288 else if (secure_transport)
1289 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290 else
1291 desc->set_protocol(kMediaProtocolAvpf);
1292}
1293
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001294// Gets the TransportInfo of the given |content_name| from the
1295// |current_description|. If doesn't exist, returns a new one.
1296static const TransportDescription* GetTransportDescription(
1297 const std::string& content_name,
1298 const SessionDescription* current_description) {
1299 const TransportDescription* desc = NULL;
1300 if (current_description) {
1301 const TransportInfo* info =
1302 current_description->GetTransportInfoByName(content_name);
1303 if (info) {
1304 desc = &info->description;
1305 }
1306 }
1307 return desc;
1308}
1309
1310// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001311static bool IsDtlsActive(const ContentInfo* content,
1312 const SessionDescription* current_description) {
1313 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001314 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001315 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001316
zhihuang1c378ed2017-08-17 14:10:50 -07001317 size_t msection_index = content - &current_description->contents()[0];
1318
1319 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001320 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001321 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001322
zhihuang1c378ed2017-08-17 14:10:50 -07001323 return current_description->transport_infos()[msection_index]
1324 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001325}
1326
Steve Anton8ffb9c32017-08-31 15:45:38 -07001327void MediaDescriptionOptions::AddAudioSender(
1328 const std::string& track_id,
1329 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001330 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001331 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001332}
1333
Steve Anton8ffb9c32017-08-31 15:45:38 -07001334void MediaDescriptionOptions::AddVideoSender(
1335 const std::string& track_id,
1336 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001337 const std::vector<RidDescription>& rids,
1338 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001339 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001340 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001341 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1342 << "RIDs are the compliant way to indicate simulcast.";
1343 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1344 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1345 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001346}
1347
zhihuang1c378ed2017-08-17 14:10:50 -07001348void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1349 const std::string& stream_id) {
1350 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001351 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1352 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001353 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001354}
1355
Steve Anton8ffb9c32017-08-31 15:45:38 -07001356void MediaDescriptionOptions::AddSenderInternal(
1357 const std::string& track_id,
1358 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001359 const std::vector<RidDescription>& rids,
1360 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001361 int num_sim_layers) {
1362 // TODO(steveanton): Support any number of stream ids.
1363 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001364 SenderOptions options;
1365 options.track_id = track_id;
1366 options.stream_ids = stream_ids;
1367 options.simulcast_layers = simulcast_layers;
1368 options.rids = rids;
1369 options.num_sim_layers = num_sim_layers;
1370 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001371}
1372
zhihuang1c378ed2017-08-17 14:10:50 -07001373bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001374 return absl::c_any_of(
1375 media_description_options,
1376 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001377}
1378
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001379MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001380 const TransportDescriptionFactory* transport_desc_factory,
1381 rtc::UniqueRandomIdGenerator* ssrc_generator)
1382 : ssrc_generator_(ssrc_generator),
1383 transport_desc_factory_(transport_desc_factory) {
1384 RTC_DCHECK(ssrc_generator_);
1385}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001386
1387MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1388 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001389 const TransportDescriptionFactory* transport_desc_factory,
1390 rtc::UniqueRandomIdGenerator* ssrc_generator)
1391 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001392 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1393 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001395 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001396 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001397 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001398 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001399}
1400
ossudedfd282016-06-14 07:12:39 -07001401const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1402 const {
ossu075af922016-06-14 03:29:38 -07001403 return audio_sendrecv_codecs_;
1404}
1405
1406const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1407 return audio_send_codecs_;
1408}
1409
1410const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1411 return audio_recv_codecs_;
1412}
1413
1414void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001415 const AudioCodecs& send_codecs,
1416 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001417 audio_send_codecs_ = send_codecs;
1418 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001419 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420}
1421
Amit Hilbuch77938e62018-12-21 09:23:38 -08001422static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1423 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001424
1425 rtc::UniqueNumberGenerator<int> unique_id_generator;
1426 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1427 for (const webrtc::RtpExtension& extension : *extensions) {
1428 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1429 RTC_DCHECK(collision_free);
1430 }
1431
Amit Hilbuch77938e62018-12-21 09:23:38 -08001432 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001433 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1434 unique_id_generator()));
1435 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1436 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001437 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001438 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001439}
1440
1441RtpHeaderExtensions
1442MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1443 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1444 if (is_unified_plan_) {
1445 AddUnifiedPlanExtensions(&extensions);
1446 }
1447
1448 return extensions;
1449}
1450
1451RtpHeaderExtensions
1452MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1453 RtpHeaderExtensions extensions = video_rtp_extensions_;
1454 if (is_unified_plan_) {
1455 AddUnifiedPlanExtensions(&extensions);
1456 }
1457
1458 return extensions;
1459}
1460
Steve Anton6fe1fba2018-12-11 10:15:23 -08001461std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001462 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001464 // Must have options for each existing section.
1465 if (current_description) {
1466 RTC_DCHECK_LE(current_description->contents().size(),
1467 session_options.media_description_options.size());
1468 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001470 IceCredentialsIterator ice_credentials(
1471 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001472
1473 std::vector<const ContentInfo*> current_active_contents;
1474 if (current_description) {
1475 current_active_contents =
1476 GetActiveContents(*current_description, session_options);
1477 }
1478
1479 StreamParamsVec current_streams =
1480 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481
zhihuang1c378ed2017-08-17 14:10:50 -07001482 AudioCodecs offer_audio_codecs;
1483 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001484 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001485 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001486 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001487
zhihuang1c378ed2017-08-17 14:10:50 -07001488 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001490 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001491 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001492 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001493 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494
1495 RtpHeaderExtensions audio_rtp_extensions;
1496 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001497 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1498 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499
Steve Anton5c72e712018-12-10 14:25:30 -08001500 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001501
zhihuang1c378ed2017-08-17 14:10:50 -07001502 // Iterate through the media description options, matching with existing media
1503 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001504 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001505 for (const MediaDescriptionOptions& media_description_options :
1506 session_options.media_description_options) {
1507 const ContentInfo* current_content = nullptr;
1508 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001509 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001510 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001511 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001512 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001513 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001514 media_description_options.type));
1515 }
1516 switch (media_description_options.type) {
1517 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001518 if (!AddAudioContentForOffer(
1519 media_description_options, session_options, current_content,
1520 current_description, audio_rtp_extensions, offer_audio_codecs,
1521 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001522 return nullptr;
1523 }
1524 break;
1525 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001526 if (!AddVideoContentForOffer(
1527 media_description_options, session_options, current_content,
1528 current_description, video_rtp_extensions, offer_video_codecs,
1529 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001530 return nullptr;
1531 }
1532 break;
1533 case MEDIA_TYPE_DATA:
1534 if (!AddDataContentForOffer(media_description_options, session_options,
1535 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001536 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001537 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001538 return nullptr;
1539 }
1540 break;
1541 default:
1542 RTC_NOTREACHED();
1543 }
1544 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545 }
1546
1547 // Bundle the contents together, if we've been asked to do so, and update any
1548 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001549 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001551 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001552 if (content.rejected) {
1553 continue;
1554 }
zhihuang1c378ed2017-08-17 14:10:50 -07001555 // TODO(deadbeef): There are conditions that make bundling two media
1556 // descriptions together illegal. For example, they use the same payload
1557 // type to represent different codecs, or same IDs for different header
1558 // extensions. We need to detect this and not try to bundle those media
1559 // descriptions together.
1560 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561 }
Steve Anton2bed3972019-01-04 17:04:30 -08001562 if (!offer_bundle.content_names().empty()) {
1563 offer->AddGroup(offer_bundle);
1564 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1565 RTC_LOG(LS_ERROR)
1566 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1567 return nullptr;
1568 }
1569 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1570 RTC_LOG(LS_ERROR)
1571 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1572 return nullptr;
1573 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 }
1575 }
Steve Antone831b8c2018-02-01 12:22:16 -08001576
1577 // The following determines how to signal MSIDs to ensure compatibility with
1578 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001579 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001580 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1581 // Plan answerers will look at a=msid and Plan B answerers will look at the
1582 // a=ssrc MSID line.
1583 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1584 cricket::kMsidSignalingSsrcAttribute);
1585 } else {
1586 // Plan B always signals MSID using a=ssrc lines.
1587 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1588 }
1589
Johannes Kron89f874e2018-11-12 10:25:48 +01001590 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1591
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001592 if (session_options.media_transport_settings.has_value()) {
1593 offer->AddMediaTransportSetting(
1594 session_options.media_transport_settings->transport_name,
1595 session_options.media_transport_settings->transport_setting);
1596 }
1597
Steve Anton6fe1fba2018-12-11 10:15:23 -08001598 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599}
1600
Steve Anton6fe1fba2018-12-11 10:15:23 -08001601std::unique_ptr<SessionDescription>
1602MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001603 const SessionDescription* offer,
1604 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001606 if (!offer) {
1607 return nullptr;
1608 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001609
Steve Anton5c72e712018-12-10 14:25:30 -08001610 // Must have options for exactly as many sections as in the offer.
1611 RTC_DCHECK_EQ(offer->contents().size(),
1612 session_options.media_description_options.size());
1613
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001614 IceCredentialsIterator ice_credentials(
1615 session_options.pooled_ice_credentials);
1616
Steve Anton5c72e712018-12-10 14:25:30 -08001617 std::vector<const ContentInfo*> current_active_contents;
1618 if (current_description) {
1619 current_active_contents =
1620 GetActiveContents(*current_description, session_options);
1621 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622
Steve Anton5c72e712018-12-10 14:25:30 -08001623 StreamParamsVec current_streams =
1624 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001625
zhihuang1c378ed2017-08-17 14:10:50 -07001626 // Get list of all possible codecs that respects existing payload type
1627 // mappings and uses a single payload type space.
1628 //
1629 // Note that these lists may be further filtered for each m= section; this
1630 // step is done just to establish the payload type mappings shared by all
1631 // sections.
1632 AudioCodecs answer_audio_codecs;
1633 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001634 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001635 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001636 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001637
1638 if (!session_options.vad_enabled) {
1639 // If application doesn't want CN codecs in answer.
1640 StripCNCodecs(&answer_audio_codecs);
1641 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001642 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001643 session_options.data_channel_type == DCT_SCTP);
1644
Steve Anton5c72e712018-12-10 14:25:30 -08001645 auto answer = absl::make_unique<SessionDescription>();
1646
1647 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1648 // group in the answer with the appropriate content names.
1649 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1650 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1651 // Transport info shared by the bundle group.
1652 std::unique_ptr<TransportInfo> bundle_transport;
1653
1654 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1655
zhihuang1c378ed2017-08-17 14:10:50 -07001656 // Iterate through the media description options, matching with existing
1657 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001658 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001659 for (const MediaDescriptionOptions& media_description_options :
1660 session_options.media_description_options) {
1661 const ContentInfo* offer_content = &offer->contents()[msection_index];
1662 // Media types and MIDs must match between the remote offer and the
1663 // MediaDescriptionOptions.
1664 RTC_DCHECK(
1665 IsMediaContentOfType(offer_content, media_description_options.type));
1666 RTC_DCHECK(media_description_options.mid == offer_content->name);
1667 const ContentInfo* current_content = nullptr;
1668 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001669 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001670 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001671 }
zhihuang1c378ed2017-08-17 14:10:50 -07001672 switch (media_description_options.type) {
1673 case MEDIA_TYPE_AUDIO:
1674 if (!AddAudioContentForAnswer(
1675 media_description_options, session_options, offer_content,
1676 offer, current_content, current_description,
1677 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001678 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001679 return nullptr;
1680 }
1681 break;
1682 case MEDIA_TYPE_VIDEO:
1683 if (!AddVideoContentForAnswer(
1684 media_description_options, session_options, offer_content,
1685 offer, current_content, current_description,
1686 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001687 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001688 return nullptr;
1689 }
1690 break;
1691 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001692 if (!AddDataContentForAnswer(
1693 media_description_options, session_options, offer_content,
1694 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001695 bundle_transport.get(), answer_rtp_data_codecs,
1696 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001697 return nullptr;
1698 }
1699 break;
1700 default:
1701 RTC_NOTREACHED();
1702 }
1703 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001704 // See if we can add the newly generated m= section to the BUNDLE group in
1705 // the answer.
1706 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001707 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001708 offer_bundle->HasContentName(added.name)) {
1709 answer_bundle.AddContentName(added.name);
1710 bundle_transport.reset(
1711 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713 }
1714
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001715 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1716 // it's empty. RFC5888 says:
1717 //
1718 // A SIP entity that receives an offer that contains an "a=group" line
1719 // with semantics that are understood MUST return an answer that
1720 // contains an "a=group" line with the same semantics.
1721 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001722 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001723 }
deadbeefb7892532017-02-22 19:35:18 -08001724
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001725 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001726 // Share the same ICE credentials and crypto params across all contents,
1727 // as BUNDLE requires.
1728 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001729 RTC_LOG(LS_ERROR)
1730 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001731 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001733
deadbeefb7892532017-02-22 19:35:18 -08001734 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001735 RTC_LOG(LS_ERROR)
1736 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001737 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001738 }
1739 }
1740
Steve Antone831b8c2018-02-01 12:22:16 -08001741 // The following determines how to signal MSIDs to ensure compatibility with
1742 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001743 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001744 // Unified Plan needs to look at what the offer included to find the most
1745 // compatible answer.
1746 if (offer->msid_signaling() == 0) {
1747 // We end up here in one of three cases:
1748 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1749 // matter what we pick here.
1750 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1751 // it also doesn't matter what we pick here.
1752 // 3. Media that's either sendonly or inactive from the remote endpoint.
1753 // We don't have any information to say whether the endpoint is Plan B
1754 // or Unified Plan, so be conservative and send both.
1755 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1756 cricket::kMsidSignalingSsrcAttribute);
1757 } else if (offer->msid_signaling() ==
1758 (cricket::kMsidSignalingMediaSection |
1759 cricket::kMsidSignalingSsrcAttribute)) {
1760 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1761 // probably talking to a Unified Plan endpoint so respond with just
1762 // a=msid.
1763 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1764 } else {
1765 // Otherwise, it's clear which method the offerer is using so repeat that
1766 // back to them.
1767 answer->set_msid_signaling(offer->msid_signaling());
1768 }
1769 } else {
1770 // Plan B always signals MSID using a=ssrc lines.
1771 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1772 }
1773
Steve Anton6fe1fba2018-12-11 10:15:23 -08001774 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775}
1776
ossu075af922016-06-14 03:29:38 -07001777const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1778 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001779 switch (direction) {
1780 // If stream is inactive - generate list as if sendrecv.
1781 case RtpTransceiverDirection::kSendRecv:
1782 case RtpTransceiverDirection::kInactive:
1783 return audio_sendrecv_codecs_;
1784 case RtpTransceiverDirection::kSendOnly:
1785 return audio_send_codecs_;
1786 case RtpTransceiverDirection::kRecvOnly:
1787 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001788 }
Steve Anton1d03a752017-11-27 14:30:09 -08001789 RTC_NOTREACHED();
1790 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001791}
1792
1793const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1794 const RtpTransceiverDirection& offer,
1795 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001796 switch (answer) {
1797 // For inactive and sendrecv answers, generate lists as if we were to accept
1798 // the offer's direction. See RFC 3264 Section 6.1.
1799 case RtpTransceiverDirection::kSendRecv:
1800 case RtpTransceiverDirection::kInactive:
1801 return GetAudioCodecsForOffer(
1802 webrtc::RtpTransceiverDirectionReversed(offer));
1803 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001804 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001805 case RtpTransceiverDirection::kRecvOnly:
1806 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001807 }
Steve Anton1d03a752017-11-27 14:30:09 -08001808 RTC_NOTREACHED();
1809 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001810}
1811
Steve Anton5c72e712018-12-10 14:25:30 -08001812void MergeCodecsFromDescription(
1813 const std::vector<const ContentInfo*>& current_active_contents,
1814 AudioCodecs* audio_codecs,
1815 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001816 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001817 UsedPayloadTypes* used_pltypes) {
1818 for (const ContentInfo* content : current_active_contents) {
1819 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001820 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001821 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001822 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001823 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001824 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001825 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001826 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001827 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001828 const RtpDataContentDescription* data =
1829 content->media_description()->as_rtp_data();
1830 if (data) {
1831 // Only relevant for RTP datachannels
1832 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1833 used_pltypes);
1834 }
zhihuang1c378ed2017-08-17 14:10:50 -07001835 }
1836 }
1837}
1838
1839// Getting codecs for an offer involves these steps:
1840//
1841// 1. Construct payload type -> codec mappings for current description.
1842// 2. Add any reference codecs that weren't already present
1843// 3. For each individual media description (m= section), filter codecs based
1844// on the directional attribute (happens in another method).
1845void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001846 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 AudioCodecs* audio_codecs,
1848 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001849 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001850 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001851 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1852 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001853 UsedPayloadTypes used_pltypes;
1854 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001855 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001856
Steve Anton5c72e712018-12-10 14:25:30 -08001857 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001858 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1859 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001860 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001861}
1862
1863// Getting codecs for an answer involves these steps:
1864//
1865// 1. Construct payload type -> codec mappings for current description.
1866// 2. Add any codecs from the offer that weren't already present.
1867// 3. Add any remaining codecs that weren't already present.
1868// 4. For each individual media description (m= section), filter codecs based
1869// on the directional attribute (happens in another method).
1870void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001871 const std::vector<const ContentInfo*>& current_active_contents,
1872 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001873 AudioCodecs* audio_codecs,
1874 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001875 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001876 // First - get all codecs from the current description if the media type
1877 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1878 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001879 UsedPayloadTypes used_pltypes;
1880 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001881 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001882
1883 // Second - filter out codecs that we don't support at all and should ignore.
1884 AudioCodecs filtered_offered_audio_codecs;
1885 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001886 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001887 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001888 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1889 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001890 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001891 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1892 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1893 filtered_offered_audio_codecs,
1894 offered_audio_codec, nullptr) &&
1895 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1896 offered_audio_codec, nullptr)) {
1897 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1898 }
1899 }
1900 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1901 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001902 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001903 for (const VideoCodec& offered_video_codec : video->codecs()) {
1904 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1905 filtered_offered_video_codecs,
1906 offered_video_codec, nullptr) &&
1907 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1908 offered_video_codec, nullptr)) {
1909 filtered_offered_video_codecs.push_back(offered_video_codec);
1910 }
1911 }
1912 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001913 const RtpDataContentDescription* data =
1914 content.media_description()->as_rtp_data();
1915 if (data) {
1916 // RTP data. This part is inactive for SCTP data.
1917 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1918 if (!FindMatchingCodec<RtpDataCodec>(
1919 data->codecs(), filtered_offered_rtp_data_codecs,
1920 offered_rtp_data_codec, nullptr) &&
1921 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1922 offered_rtp_data_codec,
1923 nullptr)) {
1924 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1925 }
zhihuang1c378ed2017-08-17 14:10:50 -07001926 }
1927 }
1928 }
1929 }
1930
Steve Anton5c72e712018-12-10 14:25:30 -08001931 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001932 // |remote_offer|.
1933 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1934 &used_pltypes);
1935 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1936 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001937 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001938 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939}
1940
1941void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001942 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001943 RtpHeaderExtensions* offer_audio_extensions,
1944 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001945 // All header extensions allocated from the same range to avoid potential
1946 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001947 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001948 RtpHeaderExtensions all_regular_extensions;
1949 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950
1951 // First - get all extensions from the current description if the media type
1952 // is used.
1953 // Add them to |used_ids| so the local ids are not reused if a new media
1954 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001955 for (const ContentInfo* content : current_active_contents) {
1956 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1957 const AudioContentDescription* audio =
1958 content->media_description()->as_audio();
1959 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1960 &all_regular_extensions, &all_encrypted_extensions,
1961 &used_ids);
1962 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1963 const VideoContentDescription* video =
1964 content->media_description()->as_video();
1965 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1966 &all_regular_extensions, &all_encrypted_extensions,
1967 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968 }
1969 }
1970
Steve Anton5c72e712018-12-10 14:25:30 -08001971 // Add our default RTP header extensions that are not in the current
1972 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001973 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1974 &all_regular_extensions, &all_encrypted_extensions,
1975 &used_ids);
1976 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1977 &all_regular_extensions, &all_encrypted_extensions,
1978 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001979
jbauch5869f502017-06-29 12:31:36 -07001980 // TODO(jbauch): Support adding encrypted header extensions to existing
1981 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001982 if (enable_encrypted_rtp_header_extensions_ &&
1983 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001984 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1985 &all_encrypted_extensions, &used_ids);
1986 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1987 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001988 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989}
1990
1991bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001992 const std::string& content_name,
1993 const TransportOptions& transport_options,
1994 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001995 SessionDescription* offer_desc,
1996 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001998 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 const TransportDescription* current_tdesc =
2000 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08002001 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002002 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
2003 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08002004 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002005 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
2006 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007 }
Steve Anton06817cd2018-12-18 15:55:30 -08002008 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
2009 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010}
2011
Steve Anton1a9d3c32018-12-10 17:18:54 -08002012std::unique_ptr<TransportDescription>
2013MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 const std::string& content_name,
2015 const SessionDescription* offer_desc,
2016 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002017 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002018 bool require_transport_attributes,
2019 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002020 if (!transport_desc_factory_)
2021 return NULL;
2022 const TransportDescription* offer_tdesc =
2023 GetTransportDescription(content_name, offer_desc);
2024 const TransportDescription* current_tdesc =
2025 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08002026 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
2027 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002028 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002029}
2030
2031bool MediaSessionDescriptionFactory::AddTransportAnswer(
2032 const std::string& content_name,
2033 const TransportDescription& transport_desc,
2034 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08002035 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036 return true;
2037}
2038
zhihuang1c378ed2017-08-17 14:10:50 -07002039// |audio_codecs| = set of all possible codecs that can be used, with correct
2040// payload type mappings
2041//
2042// |supported_audio_codecs| = set of codecs that are supported for the direction
2043// of this m= section
2044//
2045// acd->codecs() = set of previously negotiated codecs for this m= section
2046//
2047// The payload types should come from audio_codecs, but the order should come
2048// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2049// change existing codec priority, and that new codecs are added with the right
2050// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002051bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002052 const MediaDescriptionOptions& media_description_options,
2053 const MediaSessionOptions& session_options,
2054 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002055 const SessionDescription* current_description,
2056 const RtpHeaderExtensions& audio_rtp_extensions,
2057 const AudioCodecs& audio_codecs,
2058 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002059 SessionDescription* desc,
2060 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002061 // Filter audio_codecs (which includes all codecs, with correctly remapped
2062 // payload types) based on transceiver direction.
2063 const AudioCodecs& supported_audio_codecs =
2064 GetAudioCodecsForOffer(media_description_options.direction);
2065
2066 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002067
2068 if (!media_description_options.codec_preferences.empty()) {
2069 // Add the codecs from the current transceiver's codec preferences.
2070 // They override any existing codecs from previous negotiations.
2071 filtered_codecs = MatchCodecPreference(
2072 media_description_options.codec_preferences, supported_audio_codecs);
2073 } else {
2074 // Add the codecs from current content if it exists and is not rejected nor
2075 // recycled.
2076 if (current_content && !current_content->rejected &&
2077 current_content->name == media_description_options.mid) {
2078 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2079 const AudioContentDescription* acd =
2080 current_content->media_description()->as_audio();
2081 for (const AudioCodec& codec : acd->codecs()) {
2082 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2083 nullptr)) {
2084 filtered_codecs.push_back(codec);
2085 }
zhihuang1c378ed2017-08-17 14:10:50 -07002086 }
2087 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002088 // Add other supported audio codecs.
2089 AudioCodec found_codec;
2090 for (const AudioCodec& codec : supported_audio_codecs) {
2091 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2092 codec, &found_codec) &&
2093 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2094 filtered_codecs, codec, nullptr)) {
2095 // Use the |found_codec| from |audio_codecs| because it has the
2096 // correctly mapped payload type.
2097 filtered_codecs.push_back(found_codec);
2098 }
zhihuang1c378ed2017-08-17 14:10:50 -07002099 }
2100 }
deadbeef44f08192015-12-15 16:20:09 -08002101
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002102 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002103 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2104 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002105
kwiberg31022942016-03-11 14:18:21 -08002106 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002107 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002108 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2109 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002110 if (!CreateMediaContentOffer(media_description_options, session_options,
2111 filtered_codecs, sdes_policy,
2112 GetCryptos(current_content), crypto_suites,
2113 audio_rtp_extensions, ssrc_generator_,
2114 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002115 return false;
2116 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002117
2118 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2119 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002120
Steve Anton4e70a722017-11-28 14:57:10 -08002121 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002122
Steve Anton5adfafd2017-12-20 16:34:00 -08002123 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002124 media_description_options.stopped, audio.release());
2125 if (!AddTransportOffer(media_description_options.mid,
2126 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002127 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002128 return false;
2129 }
2130
2131 return true;
2132}
2133
2134bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002135 const MediaDescriptionOptions& media_description_options,
2136 const MediaSessionOptions& session_options,
2137 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002138 const SessionDescription* current_description,
2139 const RtpHeaderExtensions& video_rtp_extensions,
2140 const VideoCodecs& video_codecs,
2141 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002142 SessionDescription* desc,
2143 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002144 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002145 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2146 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002147
kwiberg31022942016-03-11 14:18:21 -08002148 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002149 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002150 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2151 &crypto_suites);
2152
2153 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002154
2155 if (!media_description_options.codec_preferences.empty()) {
2156 // Add the codecs from the current transceiver's codec preferences.
2157 // They override any existing codecs from previous negotiations.
2158 filtered_codecs = MatchCodecPreference(
2159 media_description_options.codec_preferences, video_codecs_);
2160 } else {
2161 // Add the codecs from current content if it exists and is not rejected nor
2162 // recycled.
2163 if (current_content && !current_content->rejected &&
2164 current_content->name == media_description_options.mid) {
2165 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2166 const VideoContentDescription* vcd =
2167 current_content->media_description()->as_video();
2168 for (const VideoCodec& codec : vcd->codecs()) {
2169 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2170 nullptr)) {
2171 filtered_codecs.push_back(codec);
2172 }
zhihuang1c378ed2017-08-17 14:10:50 -07002173 }
2174 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002175 // Add other supported video codecs.
2176 VideoCodec found_codec;
2177 for (const VideoCodec& codec : video_codecs_) {
2178 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2179 &found_codec) &&
2180 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2181 nullptr)) {
2182 // Use the |found_codec| from |video_codecs| because it has the
2183 // correctly mapped payload type.
2184 filtered_codecs.push_back(found_codec);
2185 }
zhihuang1c378ed2017-08-17 14:10:50 -07002186 }
2187 }
2188
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002189 if (!CreateMediaContentOffer(media_description_options, session_options,
2190 filtered_codecs, sdes_policy,
2191 GetCryptos(current_content), crypto_suites,
2192 video_rtp_extensions, ssrc_generator_,
2193 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002194 return false;
2195 }
2196
zhihuang1c378ed2017-08-17 14:10:50 -07002197 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002198
2199 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2200 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002201
Steve Anton4e70a722017-11-28 14:57:10 -08002202 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002203
Steve Anton5adfafd2017-12-20 16:34:00 -08002204 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002205 media_description_options.stopped, video.release());
2206 if (!AddTransportOffer(media_description_options.mid,
2207 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002208 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002209 return false;
2210 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002211 return true;
2212}
2213
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002214bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2215 const MediaDescriptionOptions& media_description_options,
2216 const MediaSessionOptions& session_options,
2217 const ContentInfo* current_content,
2218 const SessionDescription* current_description,
2219 StreamParamsVec* current_streams,
2220 SessionDescription* desc,
2221 IceCredentialsIterator* ice_credentials) const {
2222 std::unique_ptr<SctpDataContentDescription> data(
2223 new SctpDataContentDescription());
2224
2225 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2226
2227 cricket::SecurePolicy sdes_policy =
2228 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2229 : secure();
2230 std::vector<std::string> crypto_suites;
2231 // SDES doesn't make sense for SCTP, so we disable it, and we only
2232 // get SDES crypto suites for RTP-based data channels.
2233 sdes_policy = cricket::SEC_DISABLED;
2234 // Unlike SetMediaProtocol below, we need to set the protocol
2235 // before we call CreateMediaContentOffer. Otherwise,
2236 // CreateMediaContentOffer won't know this is SCTP and will
2237 // generate SSRCs rather than SIDs.
Harald Alvestrandc3f48202019-05-14 17:27:11 +02002238 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002239 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002240 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002241 if (!CreateContentOffer(media_description_options, session_options,
2242 sdes_policy, GetCryptos(current_content),
2243 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2244 current_streams, data.get())) {
2245 return false;
2246 }
2247
2248 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
2249 data.release());
2250 if (!AddTransportOffer(media_description_options.mid,
2251 media_description_options.transport_options,
2252 current_description, desc, ice_credentials)) {
2253 return false;
2254 }
2255 return true;
2256}
2257
2258bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2259 const MediaDescriptionOptions& media_description_options,
2260 const MediaSessionOptions& session_options,
2261 const ContentInfo* current_content,
2262 const SessionDescription* current_description,
2263 const RtpDataCodecs& rtp_data_codecs,
2264 StreamParamsVec* current_streams,
2265 SessionDescription* desc,
2266 IceCredentialsIterator* ice_credentials) const {
2267 std::unique_ptr<RtpDataContentDescription> data(
2268 new RtpDataContentDescription());
2269 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2270
2271 cricket::SecurePolicy sdes_policy =
2272 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2273 : secure();
2274 std::vector<std::string> crypto_suites;
2275 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2276 &crypto_suites);
2277 if (!CreateMediaContentOffer(media_description_options, session_options,
2278 rtp_data_codecs, sdes_policy,
2279 GetCryptos(current_content), crypto_suites,
2280 RtpHeaderExtensions(), ssrc_generator_,
2281 current_streams, data.get())) {
2282 return false;
2283 }
2284
2285 data->set_bandwidth(kDataMaxBandwidth);
2286 SetMediaProtocol(secure_transport, data.get());
2287 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
2288 media_description_options.stopped, data.release());
2289 if (!AddTransportOffer(media_description_options.mid,
2290 media_description_options.transport_options,
2291 current_description, desc, ice_credentials)) {
2292 return false;
2293 }
2294 return true;
2295}
2296
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002297bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002298 const MediaDescriptionOptions& media_description_options,
2299 const MediaSessionOptions& session_options,
2300 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002301 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002302 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002303 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002304 SessionDescription* desc,
2305 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002306 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2307 // If the DataChannel type is not specified, use the DataChannel type in
2308 // the current description.
2309 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002310 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002311 is_sctp = (current_content->media_description()->protocol() ==
2312 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002313 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002314 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002315 return AddSctpDataContentForOffer(
2316 media_description_options, session_options, current_content,
2317 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002318 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002319 return AddRtpDataContentForOffer(media_description_options, session_options,
2320 current_content, current_description,
2321 rtp_data_codecs, current_streams, desc,
2322 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002323 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002324}
2325
zhihuang1c378ed2017-08-17 14:10:50 -07002326// |audio_codecs| = set of all possible codecs that can be used, with correct
2327// payload type mappings
2328//
2329// |supported_audio_codecs| = set of codecs that are supported for the direction
2330// of this m= section
2331//
2332// acd->codecs() = set of previously negotiated codecs for this m= section
2333//
2334// The payload types should come from audio_codecs, but the order should come
2335// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2336// change existing codec priority, and that new codecs are added with the right
2337// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002338bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002339 const MediaDescriptionOptions& media_description_options,
2340 const MediaSessionOptions& session_options,
2341 const ContentInfo* offer_content,
2342 const SessionDescription* offer_description,
2343 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002344 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002345 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002346 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002347 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002348 SessionDescription* answer,
2349 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002350 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002351 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002352 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002353
Steve Anton1a9d3c32018-12-10 17:18:54 -08002354 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002355 media_description_options.mid, offer_description,
2356 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002357 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002358 if (!audio_transport) {
2359 return false;
2360 }
2361
zhihuang1c378ed2017-08-17 14:10:50 -07002362 // Pick codecs based on the requested communications direction in the offer
2363 // and the selected direction in the answer.
2364 // Note these will be filtered one final time in CreateMediaContentAnswer.
2365 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002366 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002367 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002368 AudioCodecs supported_audio_codecs =
2369 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2370
2371 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002372
2373 if (!media_description_options.codec_preferences.empty()) {
2374 filtered_codecs = MatchCodecPreference(
2375 media_description_options.codec_preferences, supported_audio_codecs);
2376 } else {
2377 // Add the codecs from current content if it exists and is not rejected nor
2378 // recycled.
2379 if (current_content && !current_content->rejected &&
2380 current_content->name == media_description_options.mid) {
2381 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2382 const AudioContentDescription* acd =
2383 current_content->media_description()->as_audio();
2384 for (const AudioCodec& codec : acd->codecs()) {
2385 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2386 nullptr)) {
2387 filtered_codecs.push_back(codec);
2388 }
zhihuang1c378ed2017-08-17 14:10:50 -07002389 }
2390 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002391 // Add other supported audio codecs.
2392 for (const AudioCodec& codec : supported_audio_codecs) {
2393 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2394 codec, nullptr) &&
2395 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2396 filtered_codecs, codec, nullptr)) {
2397 // We should use the local codec with local parameters and the codec id
2398 // would be correctly mapped in |NegotiateCodecs|.
2399 filtered_codecs.push_back(codec);
2400 }
zhihuang1c378ed2017-08-17 14:10:50 -07002401 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002402 }
2403
zhihuang1c378ed2017-08-17 14:10:50 -07002404 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2405 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002406 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002407 new AudioContentDescription());
2408 // Do not require or create SDES cryptos if DTLS is used.
2409 cricket::SecurePolicy sdes_policy =
2410 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002411 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2412 media_description_options, session_options,
2413 ssrc_generator_, current_streams,
2414 audio_answer.get())) {
2415 return false;
2416 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002417 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002418 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002419 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002420 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002421 enable_encrypted_rtp_header_extensions_, current_streams,
2422 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002423 return false; // Fails the session setup.
2424 }
2425
deadbeefb7892532017-02-22 19:35:18 -08002426 bool secure = bundle_transport ? bundle_transport->description.secure()
2427 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002428 bool rejected = media_description_options.stopped ||
2429 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002430 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2431 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002432 if (!AddTransportAnswer(media_description_options.mid,
2433 *(audio_transport.get()), answer)) {
2434 return false;
2435 }
2436
2437 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002438 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2439 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002440 }
2441
zhihuang1c378ed2017-08-17 14:10:50 -07002442 answer->AddContent(media_description_options.mid, offer_content->type,
2443 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002444 return true;
2445}
2446
2447bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002448 const MediaDescriptionOptions& media_description_options,
2449 const MediaSessionOptions& session_options,
2450 const ContentInfo* offer_content,
2451 const SessionDescription* offer_description,
2452 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002453 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002454 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002455 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002456 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002457 SessionDescription* answer,
2458 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002459 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002460 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002461 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002462
Steve Anton1a9d3c32018-12-10 17:18:54 -08002463 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002464 media_description_options.mid, offer_description,
2465 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002466 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002467 if (!video_transport) {
2468 return false;
2469 }
2470
zhihuang1c378ed2017-08-17 14:10:50 -07002471 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002472
2473 if (!media_description_options.codec_preferences.empty()) {
2474 filtered_codecs = MatchCodecPreference(
2475 media_description_options.codec_preferences, video_codecs_);
2476 } else {
2477 // Add the codecs from current content if it exists and is not rejected nor
2478 // recycled.
2479 if (current_content && !current_content->rejected &&
2480 current_content->name == media_description_options.mid) {
2481 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2482 const VideoContentDescription* vcd =
2483 current_content->media_description()->as_video();
2484 for (const VideoCodec& codec : vcd->codecs()) {
2485 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2486 nullptr)) {
2487 filtered_codecs.push_back(codec);
2488 }
zhihuang1c378ed2017-08-17 14:10:50 -07002489 }
2490 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002491 // Add other supported video codecs.
2492 for (const VideoCodec& codec : video_codecs_) {
2493 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2494 nullptr) &&
2495 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2496 nullptr)) {
2497 // We should use the local codec with local parameters and the codec id
2498 // would be correctly mapped in |NegotiateCodecs|.
2499 filtered_codecs.push_back(codec);
2500 }
zhihuang1c378ed2017-08-17 14:10:50 -07002501 }
2502 }
2503
2504 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2505 session_options.bundle_enabled;
2506
kwiberg31022942016-03-11 14:18:21 -08002507 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002508 new VideoContentDescription());
2509 // Do not require or create SDES cryptos if DTLS is used.
2510 cricket::SecurePolicy sdes_policy =
2511 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002512 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2513 media_description_options, session_options,
2514 ssrc_generator_, current_streams,
2515 video_answer.get())) {
2516 return false;
2517 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002518 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002519 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002520 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002521 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002522 enable_encrypted_rtp_header_extensions_, current_streams,
2523 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002524 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002525 }
deadbeefb7892532017-02-22 19:35:18 -08002526 bool secure = bundle_transport ? bundle_transport->description.secure()
2527 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002528 bool rejected = media_description_options.stopped ||
2529 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002530 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2531 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002532 if (!AddTransportAnswer(media_description_options.mid,
2533 *(video_transport.get()), answer)) {
2534 return false;
2535 }
2536
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002537 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002538 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002539 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002540 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2541 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002542 }
zhihuang1c378ed2017-08-17 14:10:50 -07002543 answer->AddContent(media_description_options.mid, offer_content->type,
2544 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002545 return true;
2546}
2547
2548bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002549 const MediaDescriptionOptions& media_description_options,
2550 const MediaSessionOptions& session_options,
2551 const ContentInfo* offer_content,
2552 const SessionDescription* offer_description,
2553 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002554 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002555 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002556 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002557 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002558 SessionDescription* answer,
2559 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002560 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002561 media_description_options.mid, offer_description,
2562 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002563 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002564 if (!data_transport) {
2565 return false;
2566 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002567
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002568 // Do not require or create SDES cryptos if DTLS is used.
2569 cricket::SecurePolicy sdes_policy =
2570 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002571 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2572 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002573 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002574 std::unique_ptr<MediaContentDescription> data_answer;
2575 if (offer_content->media_description()->as_sctp()) {
2576 // SCTP data content
2577 data_answer = absl::make_unique<SctpDataContentDescription>();
2578 const SctpDataContentDescription* offer_data_description =
2579 offer_content->media_description()->as_sctp();
2580 // Respond with the offerer's proto, whatever it is.
2581 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
2582 if (!CreateMediaContentAnswer(
2583 offer_data_description, media_description_options, session_options,
2584 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2585 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2586 current_streams, bundle_enabled, data_answer.get())) {
2587 return false; // Fails the session setup.
2588 }
2589 // Respond with sctpmap if the offer uses sctpmap.
2590 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2591 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2592 } else {
2593 // RTP offer
2594 data_answer = absl::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002595
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002596 const RtpDataContentDescription* offer_data_description =
2597 offer_content->media_description()->as_rtp_data();
2598 RTC_CHECK(offer_data_description);
2599 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2600 media_description_options, session_options,
2601 ssrc_generator_, current_streams,
2602 data_answer->as_rtp_data())) {
2603 return false;
2604 }
2605 if (!CreateMediaContentAnswer(
2606 offer_data_description, media_description_options, session_options,
2607 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2608 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2609 current_streams, bundle_enabled, data_answer.get())) {
2610 return false; // Fails the session setup.
2611 }
2612 }
Steve Anton46afbf92019-05-10 11:15:18 -07002613
deadbeefb7892532017-02-22 19:35:18 -08002614 bool secure = bundle_transport ? bundle_transport->description.secure()
2615 : data_transport->secure();
2616
zhihuang1c378ed2017-08-17 14:10:50 -07002617 bool rejected = session_options.data_channel_type == DCT_NONE ||
2618 media_description_options.stopped ||
2619 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002620 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2621 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002622 if (!AddTransportAnswer(media_description_options.mid,
2623 *(data_transport.get()), answer)) {
2624 return false;
2625 }
2626
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002627 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002628 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002629 } else {
2630 // RFC 3264
2631 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002632 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002633 }
zhihuang1c378ed2017-08-17 14:10:50 -07002634 answer->AddContent(media_description_options.mid, offer_content->type,
2635 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002636 return true;
2637}
2638
zhihuang1c378ed2017-08-17 14:10:50 -07002639void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2640 audio_sendrecv_codecs_.clear();
2641 all_audio_codecs_.clear();
2642 // Compute the audio codecs union.
2643 for (const AudioCodec& send : audio_send_codecs_) {
2644 all_audio_codecs_.push_back(send);
2645 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2646 send, nullptr)) {
2647 // It doesn't make sense to have an RTX codec we support sending but not
2648 // receiving.
2649 RTC_DCHECK(!IsRtxCodec(send));
2650 }
2651 }
2652 for (const AudioCodec& recv : audio_recv_codecs_) {
2653 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2654 recv, nullptr)) {
2655 all_audio_codecs_.push_back(recv);
2656 }
2657 }
2658 // Use NegotiateCodecs to merge our codec lists, since the operation is
2659 // essentially the same. Put send_codecs as the offered_codecs, which is the
2660 // order we'd like to follow. The reasoning is that encoding is usually more
2661 // expensive than decoding, and prioritizing a codec in the send list probably
2662 // means it's a codec we can handle efficiently.
2663 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002664 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002665}
2666
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002668 return (content && (content->type == MediaProtocolType::kRtp ||
2669 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670}
2671
2672bool IsAudioContent(const ContentInfo* content) {
2673 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2674}
2675
2676bool IsVideoContent(const ContentInfo* content) {
2677 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2678}
2679
2680bool IsDataContent(const ContentInfo* content) {
2681 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2682}
2683
deadbeef0ed85b22016-02-23 17:24:52 -08002684const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2685 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002686 for (const ContentInfo& content : contents) {
2687 if (IsMediaContentOfType(&content, media_type)) {
2688 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689 }
2690 }
deadbeef0ed85b22016-02-23 17:24:52 -08002691 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692}
2693
2694const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2695 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2696}
2697
2698const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2699 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2700}
2701
2702const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2703 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2704}
2705
Steve Antonad7bffc2018-01-22 10:21:56 -08002706const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2707 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002708 if (sdesc == nullptr) {
2709 return nullptr;
2710 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711
2712 return GetFirstMediaContent(sdesc->contents(), media_type);
2713}
2714
2715const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2716 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2717}
2718
2719const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2720 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2721}
2722
2723const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2724 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2725}
2726
2727const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002728 const SessionDescription* sdesc,
2729 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002731 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732}
2733
2734const AudioContentDescription* GetFirstAudioContentDescription(
2735 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002736 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2737 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002738}
2739
2740const VideoContentDescription* GetFirstVideoContentDescription(
2741 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002742 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2743 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744}
2745
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002746const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2747 const SessionDescription* sdesc) {
2748 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2749 return desc ? desc->as_rtp_data() : nullptr;
2750}
2751
2752const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2753 const SessionDescription* sdesc) {
2754 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2755 return desc ? desc->as_sctp() : nullptr;
2756}
2757
2758// Returns a shim representing either an SctpDataContentDescription
2759// or an RtpDataContentDescription, as appropriate.
2760// TODO(bugs.webrtc.org/10597): Remove together with shim.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761const DataContentDescription* GetFirstDataContentDescription(
2762 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002763 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2764 return desc ? desc->as_data() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765}
2766
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002767//
2768// Non-const versions of the above functions.
2769//
2770
Steve Anton36b29d12017-10-30 09:57:42 -07002771ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002772 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002773 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002774 if (IsMediaContentOfType(&content, media_type)) {
2775 return &content;
2776 }
2777 }
2778 return nullptr;
2779}
2780
Steve Anton36b29d12017-10-30 09:57:42 -07002781ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002782 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2783}
2784
Steve Anton36b29d12017-10-30 09:57:42 -07002785ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002786 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2787}
2788
Steve Anton36b29d12017-10-30 09:57:42 -07002789ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002790 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2791}
2792
Steve Antonad7bffc2018-01-22 10:21:56 -08002793ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2794 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002795 if (sdesc == nullptr) {
2796 return nullptr;
2797 }
2798
Steve Anton36b29d12017-10-30 09:57:42 -07002799 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002800}
2801
2802ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2803 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2804}
2805
2806ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2807 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2808}
2809
2810ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2811 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2812}
2813
2814MediaContentDescription* GetFirstMediaContentDescription(
2815 SessionDescription* sdesc,
2816 MediaType media_type) {
2817 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002818 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002819}
2820
2821AudioContentDescription* GetFirstAudioContentDescription(
2822 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002823 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2824 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002825}
2826
2827VideoContentDescription* GetFirstVideoContentDescription(
2828 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002829 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2830 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002831}
2832
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002833RtpDataContentDescription* GetFirstRtpDataContentDescription(
2834 SessionDescription* sdesc) {
2835 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2836 return desc ? desc->as_rtp_data() : nullptr;
2837}
2838
2839SctpDataContentDescription* GetFirstSctpDataContentDescription(
2840 SessionDescription* sdesc) {
2841 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2842 return desc ? desc->as_sctp() : nullptr;
2843}
2844
2845// Returns shim
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002846DataContentDescription* GetFirstDataContentDescription(
2847 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002848 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2849 return desc ? desc->as_data() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002850}
2851
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002852} // namespace cricket