blob: fe11d447020919a1e2c8810c6e4ddafd2237153c [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/media_session.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
Elad Alon157540a2019-02-08 23:37:52 +010013#include <algorithm>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve Anton64b626b2019-01-28 17:25:26 -080021#include "absl/algorithm/container.h"
Steve Anton5c72e712018-12-10 14:25:30 -080022#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020023#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020024#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "media/base/media_constants.h"
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +020028#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "p2p/base/p2p_constants.h"
30#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020031#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/rtp_media_utils.h"
33#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/checks.h"
35#include "rtc_base/helpers.h"
36#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020037#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080038#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080041
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080042using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080043using webrtc::RtpTransceiverDirection;
44
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046
Benjamin Wrighta54daf12018-10-11 15:33:17 -070047void GetSupportedSdesCryptoSuiteNames(
48 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
49 const webrtc::CryptoOptions& crypto_options,
50 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070052 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080053 for (const auto crypto : crypto_suites) {
54 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
55 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080056}
Elad Alon157540a2019-02-08 23:37:52 +010057
terelius8c011e52016-04-26 05:28:11 -070058} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60namespace cricket {
61
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062// RTP Profile names
63// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
64// RFC4585
65const char kMediaProtocolAvpf[] = "RTP/AVPF";
66// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000067const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
68
deadbeeff3938292015-07-15 12:20:53 -070069// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
70// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071const char kMediaProtocolSavpf[] = "RTP/SAVPF";
72
deadbeef8b7e9ad2017-05-25 09:38:55 -070073// Note that the below functions support some protocol strings purely for
74// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
75// and Interoperability.
76
77static bool IsDtlsRtp(const std::string& protocol) {
78 // Most-likely values first.
79 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
80 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
81}
82
83static bool IsPlainRtp(const std::string& protocol) {
84 // Most-likely values first.
85 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
86 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
87}
88
Steve Anton1d03a752017-11-27 14:30:09 -080089static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
90 RtpTransceiverDirection offer,
91 RtpTransceiverDirection wants) {
92 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
93 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
94 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
95 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
96 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
97 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070098}
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100static bool IsMediaContentOfType(const ContentInfo* content,
101 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800102 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103 return false;
104 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800105 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106}
107
Yves Gerey665174f2018-06-19 15:03:05 +0200108static bool CreateCryptoParams(int tag,
109 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700110 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700111 int key_len;
112 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200113 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
114 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return false;
116 }
jbauchcb560652016-08-04 05:20:32 -0700117
118 int master_key_len = key_len + salt_len;
119 std::string master_key;
120 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
121 return false;
122 }
123
kwiberg352444f2016-11-28 15:58:53 -0800124 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700125 std::string key = rtc::Base64::Encode(master_key);
126
Steve Anton3a66edf2018-09-10 12:57:37 -0700127 crypto_out->tag = tag;
128 crypto_out->cipher_suite = cipher;
129 crypto_out->key_params = kInline;
130 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 return true;
132}
133
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700135 CryptoParamsVec* cryptos_out) {
136 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Steve Anton3a66edf2018-09-10 12:57:37 -0700138 cryptos_out->resize(size + 1);
139 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140}
141
142void AddMediaCryptos(const CryptoParamsVec& cryptos,
143 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700144 for (const CryptoParams& crypto : cryptos) {
145 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 }
147}
148
149bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
150 MediaContentDescription* media) {
151 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700152 for (const std::string& crypto_suite : crypto_suites) {
153 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 return false;
155 }
156 }
157 AddMediaCryptos(cryptos, media);
158 return true;
159}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
zhihuang1c378ed2017-08-17 14:10:50 -0700161const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800162 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700163 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800165 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
168bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
169 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700170 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800171 auto it = absl::c_find_if(
172 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700173 if (it == cryptos.end()) {
174 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700176 *crypto_out = *it;
177 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178}
179
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700180// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
181// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700182void GetSupportedAudioSdesCryptoSuites(
183 const webrtc::CryptoOptions& crypto_options,
184 std::vector<int>* crypto_suites) {
185 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
188 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700189 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700190 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
191 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800192 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193}
194
deadbeef7914b8c2017-04-21 03:23:33 -0700195void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700196 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800197 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700198 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
199 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200}
201
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700202void GetSupportedVideoSdesCryptoSuites(
203 const webrtc::CryptoOptions& crypto_options,
204 std::vector<int>* crypto_suites) {
205 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700206 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
207 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
208 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800209 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
deadbeef7914b8c2017-04-21 03:23:33 -0700212void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700213 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800214 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700215 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedDataSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
227}
228
229void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700231 std::vector<std::string>* crypto_suite_names) {
232 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800234}
235
jbauchcb560652016-08-04 05:20:32 -0700236// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700237// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
238// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700239// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240static bool SelectCrypto(const MediaContentDescription* offer,
241 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700242 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700243 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
245 const CryptoParamsVec& cryptos = offer->cryptos();
246
Steve Anton3a66edf2018-09-10 12:57:37 -0700247 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700248 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700249 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
250 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
251 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700252 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700253 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 }
255 }
256 return false;
257}
258
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800260static StreamParamsVec GetCurrentStreamParams(
261 const std::vector<const ContentInfo*>& active_local_contents) {
262 StreamParamsVec stream_params;
263 for (const ContentInfo* content : active_local_contents) {
264 for (const StreamParams& params : content->media_description()->streams()) {
265 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 }
267 }
Steve Anton5c72e712018-12-10 14:25:30 -0800268 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269}
270
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000271// Filters the data codecs for the data channel type.
272void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
273 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700274 const char* codec_name =
275 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700276 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
277 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200278 return absl::EqualsIgnoreCase(codec.name,
279 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700280 }),
281 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000282}
283
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284template <typename IdStruct>
285class UsedIds {
286 public:
287 UsedIds(int min_allowed_id, int max_allowed_id)
288 : min_allowed_id_(min_allowed_id),
289 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200290 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291
292 // Loops through all Id in |ids| and changes its id if it is
293 // already in use by another IdStruct. Call this methods with all Id
294 // in a session description to make sure no duplicate ids exists.
295 // Note that typename Id must be a type of IdStruct.
296 template <typename Id>
297 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700298 for (const Id& id : *ids) {
299 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 }
301 }
302
303 // Finds and sets an unused id if the |idstruct| id is already in use.
304 void FindAndSetIdUsed(IdStruct* idstruct) {
305 const int original_id = idstruct->id;
306 int new_id = idstruct->id;
307
308 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
309 // If the original id is not in range - this is an id that can't be
310 // dynamically changed.
311 return;
312 }
313
314 if (IsIdUsed(original_id)) {
315 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100316 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
317 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318 idstruct->id = new_id;
319 }
320 SetIdUsed(new_id);
321 }
322
323 private:
324 // Returns the first unused id in reverse order.
325 // This hopefully reduce the risk of more collisions. We want to change the
326 // default ids as little as possible.
327 int FindUnusedId() {
328 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
329 --next_id_;
330 }
nisseede5da42017-01-12 05:15:36 -0800331 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 return next_id_;
333 }
334
Yves Gerey665174f2018-06-19 15:03:05 +0200335 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336
Yves Gerey665174f2018-06-19 15:03:05 +0200337 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338
339 const int min_allowed_id_;
340 const int max_allowed_id_;
341 int next_id_;
342 std::set<int> id_set_;
343};
344
345// Helper class used for finding duplicate RTP payload types among audio, video
346// and data codecs. When bundle is used the payload types may not collide.
347class UsedPayloadTypes : public UsedIds<Codec> {
348 public:
349 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200350 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351
352 private:
353 static const int kDynamicPayloadTypeMin = 96;
354 static const int kDynamicPayloadTypeMax = 127;
355};
356
357// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200358// audio and video extensions. Only applies to one-byte header extensions at the
359// moment. ids > 14 will always be reported as available.
360// TODO(kron): This class needs to be refactored when we start to send two-byte
361// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700362class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363 public:
364 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200365 : UsedIds<webrtc::RtpExtension>(
366 webrtc::RtpExtension::kMinId,
367 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
369 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370};
371
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
373 const SenderOptions& sender,
374 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800375 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800376 bool include_flexfec_stream,
377 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800378 StreamParams result;
379 result.id = sender.track_id;
380
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800381 // TODO(brandtr): Update when we support multistream protection.
382 if (include_flexfec_stream && sender.num_sim_layers > 1) {
383 include_flexfec_stream = false;
384 RTC_LOG(LS_WARNING)
385 << "Our FlexFEC implementation only supports protecting "
386 "a single media streams. This session has multiple "
387 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800388 }
389
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800390 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
391 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800392
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800393 result.cname = rtcp_cname;
394 result.set_stream_ids(sender.stream_ids);
395
396 return result;
397}
398
399static bool ValidateSimulcastLayers(
400 const std::vector<RidDescription>& rids,
401 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800402 return absl::c_all_of(
403 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
404 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
405 return rid.rid == layer.rid;
406 });
407 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800408}
409
410static StreamParams CreateStreamParamsForNewSenderWithRids(
411 const SenderOptions& sender,
412 const std::string& rtcp_cname) {
413 RTC_DCHECK(!sender.rids.empty());
414 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
415 << "RIDs are the compliant way to indicate simulcast.";
416 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
417 StreamParams result;
418 result.id = sender.track_id;
419 result.cname = rtcp_cname;
420 result.set_stream_ids(sender.stream_ids);
421
422 // More than one rid should be signaled.
423 if (sender.rids.size() > 1) {
424 result.set_rids(sender.rids);
425 }
426
427 return result;
428}
429
430// Adds SimulcastDescription if indicated by the media description options.
431// MediaContentDescription should already be set up with the send rids.
432static void AddSimulcastToMediaDescription(
433 const MediaDescriptionOptions& media_description_options,
434 MediaContentDescription* description) {
435 RTC_DCHECK(description);
436
437 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800438 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
439 return !params.has_rids();
440 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800441 return;
442 }
443
444 RTC_DCHECK_EQ(1, description->streams().size())
445 << "RIDs are only supported in Unified Plan semantics.";
446 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
447 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
448 description->type() == MediaType::MEDIA_TYPE_VIDEO);
449
450 // One RID or less indicates that simulcast is not needed.
451 if (description->streams()[0].rids().size() <= 1) {
452 return;
453 }
454
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800455 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800456 SimulcastDescription simulcast;
457 simulcast.send_layers() =
458 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800459 description->set_simulcast_description(simulcast);
460}
461
zhihuang1c378ed2017-08-17 14:10:50 -0700462// Adds a StreamParams for each SenderOptions in |sender_options| to
463// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464// |current_params| - All currently known StreamParams of any media type.
465template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700466static bool AddStreamParams(
467 const std::vector<SenderOptions>& sender_options,
468 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800469 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700470 StreamParamsVec* current_streams,
471 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700472 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200473 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700474 return true;
475 }
476
Noah Richards2e7a0982015-05-18 14:02:54 -0700477 const bool include_rtx_streams =
478 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479
brandtr03d5fb12016-11-22 03:37:59 -0800480 const bool include_flexfec_stream =
481 ContainsFlexfecCodec(content_description->codecs());
482
zhihuang1c378ed2017-08-17 14:10:50 -0700483 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 // groupid is empty for StreamParams generated using
485 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700486 StreamParams* param =
487 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000488 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700489 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800490 StreamParams stream_param =
491 sender.rids.empty()
492 ?
493 // Signal SSRCs and legacy simulcast (if requested).
494 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800495 sender, rtcp_cname, include_rtx_streams,
496 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800497 :
498 // Signal RIDs and spec-compliant simulcast (if requested).
499 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
500
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 content_description->AddStream(stream_param);
502
503 // Store the new StreamParams in current_streams.
504 // This is necessary so that we can use the CNAME for other media types.
505 current_streams->push_back(stream_param);
506 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700507 // Use existing generated SSRCs/groups, but update the sync_label if
508 // necessary. This may be needed if a MediaStreamTrack was moved from one
509 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800510 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000511 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 }
513 }
514 return true;
515}
516
517// Updates the transport infos of the |sdesc| according to the given
518// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800519// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
520// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
522 SessionDescription* sdesc) {
523 // The bundle should not be empty.
524 if (!sdesc || !bundle_group.FirstContentName()) {
525 return false;
526 }
527
528 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700529 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 const TransportInfo* selected_transport_info =
531 sdesc->GetTransportInfoByName(selected_content_name);
532 if (!selected_transport_info) {
533 return false;
534 }
535
536 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700537 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700539 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800541 ConnectionRole selected_connection_role =
542 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700543 for (TransportInfo& transport_info : sdesc->transport_infos()) {
544 if (bundle_group.HasContentName(transport_info.content_name) &&
545 transport_info.content_name != selected_content_name) {
546 transport_info.description.ice_ufrag = selected_ufrag;
547 transport_info.description.ice_pwd = selected_pwd;
548 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 }
550 }
551 return true;
552}
553
554// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
555// sets it to |cryptos|.
556static bool GetCryptosByName(const SessionDescription* sdesc,
557 const std::string& content_name,
558 CryptoParamsVec* cryptos) {
559 if (!sdesc || !cryptos) {
560 return false;
561 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800563 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 return false;
565 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800566 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 return true;
568}
569
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
571// which are not available in |filter|.
572static void PruneCryptos(const CryptoParamsVec& filter,
573 CryptoParamsVec* target_cryptos) {
574 if (!target_cryptos) {
575 return;
576 }
tzik21995802018-04-26 17:38:28 +0900577
578 target_cryptos->erase(
579 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
580 // Returns true if the |crypto|'s cipher_suite is not
581 // found in |filter|.
582 [&filter](const CryptoParams& crypto) {
583 for (const CryptoParams& entry : filter) {
584 if (entry.cipher_suite == crypto.cipher_suite)
585 return false;
586 }
587 return true;
588 }),
589 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590}
591
592static bool IsRtpContent(SessionDescription* sdesc,
593 const std::string& content_name) {
594 bool is_rtp = false;
595 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800596 if (content && content->media_description()) {
597 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 }
599 return is_rtp;
600}
601
602// Updates the crypto parameters of the |sdesc| according to the given
603// |bundle_group|. The crypto parameters of all the contents within the
604// |bundle_group| should be updated to use the common subset of the
605// available cryptos.
606static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
607 SessionDescription* sdesc) {
608 // The bundle should not be empty.
609 if (!sdesc || !bundle_group.FirstContentName()) {
610 return false;
611 }
612
wu@webrtc.org78187522013-10-07 23:32:02 +0000613 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 // Get the common cryptos.
615 const ContentNames& content_names = bundle_group.content_names();
616 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700617 bool first = true;
618 for (const std::string& content_name : content_names) {
619 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 continue;
621 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000622 // The common cryptos are needed if any of the content does not have DTLS
623 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700624 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000625 common_cryptos_needed = true;
626 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700627 if (first) {
628 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700630 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 return false;
632 }
633 if (common_cryptos.empty()) {
634 // If there's no crypto params, we should just return.
635 return true;
636 }
637 } else {
638 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700639 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 return false;
641 }
642 PruneCryptos(cryptos, &common_cryptos);
643 }
644 }
645
wu@webrtc.org78187522013-10-07 23:32:02 +0000646 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 return false;
648 }
649
650 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700651 for (const std::string& content_name : content_names) {
652 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 continue;
654 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700655 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800657 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 if (!media_desc) {
659 return false;
660 }
661 media_desc->set_cryptos(common_cryptos);
662 }
663 }
664 return true;
665}
666
Steve Anton5c72e712018-12-10 14:25:30 -0800667static std::vector<const ContentInfo*> GetActiveContents(
668 const SessionDescription& description,
669 const MediaSessionOptions& session_options) {
670 std::vector<const ContentInfo*> active_contents;
671 for (size_t i = 0; i < description.contents().size(); ++i) {
672 RTC_DCHECK_LT(i, session_options.media_description_options.size());
673 const ContentInfo& content = description.contents()[i];
674 const MediaDescriptionOptions& media_options =
675 session_options.media_description_options[i];
676 if (!content.rejected && !media_options.stopped &&
677 content.name == media_options.mid) {
678 active_contents.push_back(&content);
679 }
680 }
681 return active_contents;
682}
683
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684template <class C>
685static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800686 for (const auto& codec : codecs) {
687 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 return true;
689 }
690 }
691 return false;
692}
693
694template <class C>
695static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200696 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697}
698
brandtr03d5fb12016-11-22 03:37:59 -0800699template <class C>
700static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
701 for (const auto& codec : codecs) {
702 if (IsFlexfecCodec(codec)) {
703 return true;
704 }
705 }
706 return false;
707}
708
709template <class C>
710static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200711 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800712}
713
zhihuang1c378ed2017-08-17 14:10:50 -0700714// Create a media content to be offered for the given |sender_options|,
715// according to the given options.rtcp_mux, session_options.is_muc, codecs,
716// secure_transport, crypto, and current_streams. If we don't currently have
717// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
718// created (according to crypto_suites). The created content is added to the
719// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200720static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800721 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700722 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000723 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 const CryptoParamsVec* current_cryptos,
725 const std::vector<std::string>& crypto_suites,
726 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800727 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200729 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700730 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700731 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
732 offer->set_rtcp_reduced_size(true);
733 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 offer->set_rtp_header_extensions(rtp_extensions);
735
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800736 AddSimulcastToMediaDescription(media_description_options, offer);
737
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 if (secure_policy != SEC_DISABLED) {
739 if (current_cryptos) {
740 AddMediaCryptos(*current_cryptos, offer);
741 }
742 if (offer->cryptos().empty()) {
743 if (!CreateMediaCryptos(crypto_suites, offer)) {
744 return false;
745 }
746 }
747 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748
deadbeef7af91dd2016-12-13 11:29:11 -0800749 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 return false;
751 }
752 return true;
753}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200754template <class C>
755static bool CreateMediaContentOffer(
756 const MediaDescriptionOptions& media_description_options,
757 const MediaSessionOptions& session_options,
758 const std::vector<C>& codecs,
759 const SecurePolicy& secure_policy,
760 const CryptoParamsVec* current_cryptos,
761 const std::vector<std::string>& crypto_suites,
762 const RtpHeaderExtensions& rtp_extensions,
763 UniqueRandomIdGenerator* ssrc_generator,
764 StreamParamsVec* current_streams,
765 MediaContentDescriptionImpl<C>* offer) {
766 offer->AddCodecs(codecs);
767 if (!AddStreamParams(media_description_options.sender_options,
768 session_options.rtcp_cname, ssrc_generator,
769 current_streams, offer)) {
770 return false;
771 }
772
773 return CreateContentOffer(media_description_options, session_options,
774 secure_policy, current_cryptos, crypto_suites,
775 rtp_extensions, ssrc_generator, current_streams,
776 offer);
777}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778
779template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000780static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800781 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000782 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800783 const int codec2_id) {
784 const C* codec1 = FindCodecById(codecs1, codec1_id);
785 const C* codec2 = FindCodecById(codecs2, codec2_id);
786 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000787}
788
789template <class C>
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200790static void NegotiatePacketization(const C& local_codec,
791 const C& remote_codec,
792 C* negotiated_codec) {}
793
794template <>
795void NegotiatePacketization(const VideoCodec& local_codec,
796 const VideoCodec& remote_codec,
797 VideoCodec* negotiated_codec) {
798 negotiated_codec->packetization =
799 VideoCodec::IntersectPacketization(local_codec, remote_codec);
800}
801
802template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803static void NegotiateCodecs(const std::vector<C>& local_codecs,
804 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200805 std::vector<C>* negotiated_codecs,
806 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800807 for (const C& ours : local_codecs) {
808 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700809 // Note that we intentionally only find one matching codec for each of our
810 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800811 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
812 C negotiated = ours;
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200813 NegotiatePacketization(ours, theirs, &negotiated);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800814 negotiated.IntersectFeedbackParams(theirs);
815 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800816 const auto apt_it =
817 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800818 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800819 RTC_DCHECK(apt_it != theirs.params.end());
820 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 }
Niels Möller039743e2018-10-23 10:07:25 +0200822 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800823 webrtc::H264::GenerateProfileLevelIdForAnswer(
824 ours.params, theirs.params, &negotiated.params);
825 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800826 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700827 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800828 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 }
830 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200831 if (keep_offer_order) {
832 // RFC3264: Although the answerer MAY list the formats in their desired
833 // order of preference, it is RECOMMENDED that unless there is a
834 // specific reason, the answerer list formats in the same relative order
835 // they were present in the offer.
836 // This can be skipped when the transceiver has any codec preferences.
837 std::unordered_map<int, int> payload_type_preferences;
838 int preference = static_cast<int>(offered_codecs.size() + 1);
839 for (const C& codec : offered_codecs) {
840 payload_type_preferences[codec.id] = preference--;
841 }
842 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
843 const C& b) {
844 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
845 });
deadbeef67cf2c12016-04-13 10:07:16 -0700846 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847}
848
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800849// Finds a codec in |codecs2| that matches |codec_to_match|, which is
850// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
851// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800853static bool FindMatchingCodec(const std::vector<C>& codecs1,
854 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 const C& codec_to_match,
856 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700857 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
858 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800859 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
860 return &codec == &codec_to_match;
861 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800862 for (const C& potential_match : codecs2) {
863 if (potential_match.Matches(codec_to_match)) {
864 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800865 int apt_value_1 = 0;
866 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800867 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
868 &apt_value_1) ||
869 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
870 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100871 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800872 continue;
873 }
874 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
875 apt_value_2)) {
876 continue;
877 }
878 }
879 if (found_codec) {
880 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 }
882 return true;
883 }
884 }
885 return false;
886}
887
zhihuang1c378ed2017-08-17 14:10:50 -0700888// Find the codec in |codec_list| that |rtx_codec| is associated with.
889template <class C>
890static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
891 const C& rtx_codec) {
892 std::string associated_pt_str;
893 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
894 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100895 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
896 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700897 return nullptr;
898 }
899
900 int associated_pt;
901 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100902 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
903 << " of RTX codec " << rtx_codec.name
904 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700905 return nullptr;
906 }
907
908 // Find the associated reference codec for the reference RTX codec.
909 const C* associated_codec = FindCodecById(codec_list, associated_pt);
910 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100911 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
912 << associated_pt << " for RTX codec " << rtx_codec.name
913 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700914 }
915 return associated_codec;
916}
917
918// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919// already exist in |offered_codecs| and ensure the payload types don't
920// collide.
921template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700922static void MergeCodecs(const std::vector<C>& reference_codecs,
923 std::vector<C>* offered_codecs,
924 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000925 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800926 for (const C& reference_codec : reference_codecs) {
927 if (!IsRtxCodec(reference_codec) &&
928 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
929 reference_codec, nullptr)) {
930 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 used_pltypes->FindAndSetIdUsed(&codec);
932 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000933 }
934 }
935
936 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800937 for (const C& reference_codec : reference_codecs) {
938 if (IsRtxCodec(reference_codec) &&
939 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
940 reference_codec, nullptr)) {
941 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700942 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700943 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700944 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700945 continue;
946 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800947 // Find a codec in the offered list that matches the reference codec.
948 // Its payload type may be different than the reference codec.
949 C matching_codec;
950 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800951 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100952 RTC_LOG(LS_WARNING)
953 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800954 continue;
955 }
956
957 rtx_codec.params[kCodecParamAssociatedPayloadType] =
958 rtc::ToString(matching_codec.id);
959 used_pltypes->FindAndSetIdUsed(&rtx_codec);
960 offered_codecs->push_back(rtx_codec);
961 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000962 }
963}
964
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200965template <typename Codecs>
966static Codecs MatchCodecPreference(
967 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
968 const Codecs& codecs) {
969 Codecs filtered_codecs;
970 std::set<std::string> kept_codecs_ids;
971 bool want_rtx = false;
972
973 for (const auto& codec_preference : codec_preferences) {
974 auto found_codec = absl::c_find_if(
975 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
976 webrtc::RtpCodecParameters codec_parameters =
977 codec.ToCodecParameters();
978 return codec_parameters.name == codec_preference.name &&
979 codec_parameters.kind == codec_preference.kind &&
980 codec_parameters.num_channels ==
981 codec_preference.num_channels &&
982 codec_parameters.clock_rate == codec_preference.clock_rate &&
983 codec_parameters.parameters == codec_preference.parameters;
984 });
985
986 if (found_codec != codecs.end()) {
987 filtered_codecs.push_back(*found_codec);
988 kept_codecs_ids.insert(std::to_string(found_codec->id));
989 } else if (IsRtxCodec(codec_preference)) {
990 want_rtx = true;
991 }
992 }
993
994 if (want_rtx) {
995 for (const auto& codec : codecs) {
996 if (IsRtxCodec(codec)) {
997 const auto apt =
998 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
999 if (apt != codec.params.end() &&
1000 kept_codecs_ids.count(apt->second) > 0) {
1001 filtered_codecs.push_back(codec);
1002 }
1003 }
1004 }
1005 }
1006
1007 return filtered_codecs;
1008}
1009
zhihuang1c378ed2017-08-17 14:10:50 -07001010static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
1011 const webrtc::RtpExtension& ext_to_match,
1012 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -08001013 auto it = absl::c_find_if(
1014 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
1015 // We assume that all URIs are given in a canonical
1016 // format.
1017 return extension.uri == ext_to_match.uri &&
1018 extension.encrypt == ext_to_match.encrypt;
1019 });
Steve Anton3a66edf2018-09-10 12:57:37 -07001020 if (it == extensions.end()) {
1021 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001022 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001023 if (found_extension) {
1024 *found_extension = *it;
1025 }
1026 return true;
zhihuang1c378ed2017-08-17 14:10:50 -07001027}
1028
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -07001030 const webrtc::RtpExtension& ext_to_match,
1031 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -07001032 // We assume that all URIs are given in a canonical format.
1033 const webrtc::RtpExtension* found =
1034 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
1035 ext_to_match.uri);
1036 if (!found) {
1037 return false;
1038 }
1039 if (found_extension) {
1040 *found_extension = *found;
1041 }
1042 return true;
1043}
1044
1045static bool FindByUriWithEncryptionPreference(
1046 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001047 const webrtc::RtpExtension& ext_to_match,
1048 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -07001049 webrtc::RtpExtension* found_extension) {
1050 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -07001051 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -07001053 if (extension.uri == ext_to_match.uri) {
1054 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -07001055 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001056 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -07001057 }
1058 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059 }
Steve Anton3a66edf2018-09-10 12:57:37 -07001060 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001061 }
1062 }
jbauch5869f502017-06-29 12:31:36 -07001063 if (unencrypted_extension) {
1064 if (found_extension) {
1065 *found_extension = *unencrypted_extension;
1066 }
1067 return true;
1068 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 return false;
1070}
1071
zhihuang1c378ed2017-08-17 14:10:50 -07001072// Adds all extensions from |reference_extensions| to |offered_extensions| that
1073// don't already exist in |offered_extensions| and ensure the IDs don't
1074// collide. If an extension is added, it's also added to |regular_extensions| or
1075// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1076// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1077// |offered_extensions| is for either audio or video while |regular_extensions|
1078// and |encrypted_extensions| are used for both audio and video. There could be
1079// overlap between audio extensions and video extensions.
1080static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1081 RtpHeaderExtensions* offered_extensions,
1082 RtpHeaderExtensions* regular_extensions,
1083 RtpHeaderExtensions* encrypted_extensions,
1084 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001085 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001086 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1087 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001088 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001089 if (reference_extension.encrypt) {
1090 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1091 &existing)) {
1092 offered_extensions->push_back(existing);
1093 } else {
1094 used_ids->FindAndSetIdUsed(&reference_extension);
1095 encrypted_extensions->push_back(reference_extension);
1096 offered_extensions->push_back(reference_extension);
1097 }
olka3c747662017-08-17 06:50:32 -07001098 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001099 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1100 &existing)) {
1101 offered_extensions->push_back(existing);
1102 } else {
1103 used_ids->FindAndSetIdUsed(&reference_extension);
1104 regular_extensions->push_back(reference_extension);
1105 offered_extensions->push_back(reference_extension);
1106 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001107 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108 }
1109 }
1110}
1111
jbauch5869f502017-06-29 12:31:36 -07001112static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1113 RtpHeaderExtensions* all_extensions,
1114 UsedRtpHeaderExtensionIds* used_ids) {
1115 RtpHeaderExtensions encrypted_extensions;
1116 for (const webrtc::RtpExtension& extension : *extensions) {
1117 webrtc::RtpExtension existing;
1118 // Don't add encrypted extensions again that were already included in a
1119 // previous offer or regular extensions that are also included as encrypted
1120 // extensions.
1121 if (extension.encrypt ||
1122 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1123 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001124 &existing) &&
1125 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001126 continue;
1127 }
1128
1129 if (FindByUri(*all_extensions, extension, &existing)) {
1130 encrypted_extensions.push_back(existing);
1131 } else {
1132 webrtc::RtpExtension encrypted(extension);
1133 encrypted.encrypt = true;
1134 used_ids->FindAndSetIdUsed(&encrypted);
1135 all_extensions->push_back(encrypted);
1136 encrypted_extensions.push_back(encrypted);
1137 }
1138 }
1139 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001140 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001141}
1142
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143static void NegotiateRtpHeaderExtensions(
1144 const RtpHeaderExtensions& local_extensions,
1145 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001146 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001147 RtpHeaderExtensions* negotiated_extensions) {
1148 // TransportSequenceNumberV2 is not offered by default. The special logic for
1149 // the TransportSequenceNumber extensions works as follows:
1150 // Offer Answer
1151 // V1 V1 if in local_extensions.
1152 // V1 and V2 V2 regardless of local_extensions.
1153 // V2 V2 regardless of local_extensions.
1154 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1155 webrtc::RtpExtension::FindHeaderExtensionByUri(
1156 offered_extensions,
1157 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1158
Steve Anton3a66edf2018-09-10 12:57:37 -07001159 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001160 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001161 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001162 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001163 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001164 if (transport_sequence_number_v2_offer &&
1165 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1166 // Don't respond to
1167 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1168 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001169 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001170 continue;
1171 } else {
1172 // We respond with their RTP header extension id.
1173 negotiated_extensions->push_back(theirs);
1174 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 }
1176 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001177
1178 if (transport_sequence_number_v2_offer) {
1179 // Respond that we support kTransportSequenceNumberV2Uri.
1180 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1181 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182}
1183
1184static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001185 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1186 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001187 return absl::EqualsIgnoreCase(
1188 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001189 }),
1190 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191}
1192
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001193template <class C>
1194static bool SetCodecsInAnswer(
1195 const MediaContentDescriptionImpl<C>* offer,
1196 const std::vector<C>& local_codecs,
1197 const MediaDescriptionOptions& media_description_options,
1198 const MediaSessionOptions& session_options,
1199 UniqueRandomIdGenerator* ssrc_generator,
1200 StreamParamsVec* current_streams,
1201 MediaContentDescriptionImpl<C>* answer) {
1202 std::vector<C> negotiated_codecs;
1203 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1204 media_description_options.codec_preferences.empty());
1205 answer->AddCodecs(negotiated_codecs);
1206 answer->set_protocol(offer->protocol());
1207 if (!AddStreamParams(media_description_options.sender_options,
1208 session_options.rtcp_cname, ssrc_generator,
1209 current_streams, answer)) {
1210 return false; // Something went seriously wrong.
1211 }
1212 return true;
1213}
1214
zhihuang1c378ed2017-08-17 14:10:50 -07001215// Create a media content to be answered for the given |sender_options|
1216// according to the given session_options.rtcp_mux, session_options.streams,
1217// codecs, crypto, and current_streams. If we don't currently have crypto (in
1218// current_cryptos) and it is enabled (in secure_policy), crypto is created
1219// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1220// negotiated with the offer. If the negotiation fails, this method returns
1221// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001223 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001224 const MediaDescriptionOptions& media_description_options,
1225 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001226 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 const CryptoParamsVec* current_cryptos,
1228 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001229 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001230 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001233 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001234 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001236 NegotiateRtpHeaderExtensions(
1237 local_rtp_extenstions, offer->rtp_header_extensions(),
1238 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1240
zhihuang1c378ed2017-08-17 14:10:50 -07001241 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001242 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1243 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1244 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245
1246 if (sdes_policy != SEC_DISABLED) {
1247 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001248 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1249 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 if (current_cryptos) {
1251 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1252 }
1253 answer->AddCrypto(crypto);
1254 }
1255 }
1256
deadbeef7af91dd2016-12-13 11:29:11 -08001257 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 return false;
1259 }
1260
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001261 AddSimulcastToMediaDescription(media_description_options, answer);
1262
Steve Anton4e70a722017-11-28 14:57:10 -08001263 answer->set_direction(NegotiateRtpTransceiverDirection(
1264 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001265 return true;
1266}
1267
1268static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001269 const std::string& protocol,
1270 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001271 // Since not all applications serialize and deserialize the media protocol,
1272 // we will have to accept |protocol| to be empty.
1273 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 return true;
1275 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001276
zhihuangcf5b37c2016-05-05 11:44:35 -07001277 if (type == MEDIA_TYPE_DATA) {
1278 // Check for SCTP, but also for RTP for RTP-based data channels.
1279 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1280 if (secure_transport) {
1281 // Most likely scenarios first.
1282 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1283 IsPlainRtp(protocol);
1284 } else {
1285 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1286 }
1287 }
1288
1289 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1290 // JSEP specifies.
1291 if (secure_transport) {
1292 // Most likely scenarios first.
1293 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1294 } else {
1295 return IsPlainRtp(protocol);
1296 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297}
1298
1299static void SetMediaProtocol(bool secure_transport,
1300 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001301 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001303 else if (secure_transport)
1304 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 else
1306 desc->set_protocol(kMediaProtocolAvpf);
1307}
1308
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001309// Gets the TransportInfo of the given |content_name| from the
1310// |current_description|. If doesn't exist, returns a new one.
1311static const TransportDescription* GetTransportDescription(
1312 const std::string& content_name,
1313 const SessionDescription* current_description) {
1314 const TransportDescription* desc = NULL;
1315 if (current_description) {
1316 const TransportInfo* info =
1317 current_description->GetTransportInfoByName(content_name);
1318 if (info) {
1319 desc = &info->description;
1320 }
1321 }
1322 return desc;
1323}
1324
1325// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001326static bool IsDtlsActive(const ContentInfo* content,
1327 const SessionDescription* current_description) {
1328 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001329 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001330 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001331
zhihuang1c378ed2017-08-17 14:10:50 -07001332 size_t msection_index = content - &current_description->contents()[0];
1333
1334 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001335 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001336 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001337
zhihuang1c378ed2017-08-17 14:10:50 -07001338 return current_description->transport_infos()[msection_index]
1339 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001340}
1341
Steve Anton8ffb9c32017-08-31 15:45:38 -07001342void MediaDescriptionOptions::AddAudioSender(
1343 const std::string& track_id,
1344 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001345 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001346 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001347}
1348
Steve Anton8ffb9c32017-08-31 15:45:38 -07001349void MediaDescriptionOptions::AddVideoSender(
1350 const std::string& track_id,
1351 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001352 const std::vector<RidDescription>& rids,
1353 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001354 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001355 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001356 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1357 << "RIDs are the compliant way to indicate simulcast.";
1358 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1359 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1360 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001361}
1362
zhihuang1c378ed2017-08-17 14:10:50 -07001363void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1364 const std::string& stream_id) {
1365 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001366 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1367 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001368 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001369}
1370
Steve Anton8ffb9c32017-08-31 15:45:38 -07001371void MediaDescriptionOptions::AddSenderInternal(
1372 const std::string& track_id,
1373 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001374 const std::vector<RidDescription>& rids,
1375 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001376 int num_sim_layers) {
1377 // TODO(steveanton): Support any number of stream ids.
1378 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001379 SenderOptions options;
1380 options.track_id = track_id;
1381 options.stream_ids = stream_ids;
1382 options.simulcast_layers = simulcast_layers;
1383 options.rids = rids;
1384 options.num_sim_layers = num_sim_layers;
1385 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001386}
1387
zhihuang1c378ed2017-08-17 14:10:50 -07001388bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001389 return absl::c_any_of(
1390 media_description_options,
1391 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001392}
1393
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001395 const TransportDescriptionFactory* transport_desc_factory,
1396 rtc::UniqueRandomIdGenerator* ssrc_generator)
1397 : ssrc_generator_(ssrc_generator),
1398 transport_desc_factory_(transport_desc_factory) {
1399 RTC_DCHECK(ssrc_generator_);
1400}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001401
1402MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1403 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001404 const TransportDescriptionFactory* transport_desc_factory,
1405 rtc::UniqueRandomIdGenerator* ssrc_generator)
1406 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001407 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1408 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001410 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001411 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001412 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001413 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001414}
1415
ossudedfd282016-06-14 07:12:39 -07001416const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1417 const {
ossu075af922016-06-14 03:29:38 -07001418 return audio_sendrecv_codecs_;
1419}
1420
1421const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1422 return audio_send_codecs_;
1423}
1424
1425const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1426 return audio_recv_codecs_;
1427}
1428
1429void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001430 const AudioCodecs& send_codecs,
1431 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001432 audio_send_codecs_ = send_codecs;
1433 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001434 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001435}
1436
Amit Hilbuch77938e62018-12-21 09:23:38 -08001437static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1438 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001439
1440 rtc::UniqueNumberGenerator<int> unique_id_generator;
1441 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1442 for (const webrtc::RtpExtension& extension : *extensions) {
1443 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1444 RTC_DCHECK(collision_free);
1445 }
1446
Amit Hilbuch77938e62018-12-21 09:23:38 -08001447 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001448 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1449 unique_id_generator()));
1450 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1451 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001452 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001453 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001454}
1455
1456RtpHeaderExtensions
1457MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1458 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1459 if (is_unified_plan_) {
1460 AddUnifiedPlanExtensions(&extensions);
1461 }
1462
1463 return extensions;
1464}
1465
1466RtpHeaderExtensions
1467MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1468 RtpHeaderExtensions extensions = video_rtp_extensions_;
1469 if (is_unified_plan_) {
1470 AddUnifiedPlanExtensions(&extensions);
1471 }
1472
1473 return extensions;
1474}
1475
Steve Anton6fe1fba2018-12-11 10:15:23 -08001476std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001477 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001478 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001479 // Must have options for each existing section.
1480 if (current_description) {
1481 RTC_DCHECK_LE(current_description->contents().size(),
1482 session_options.media_description_options.size());
1483 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001484
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001485 IceCredentialsIterator ice_credentials(
1486 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001487
1488 std::vector<const ContentInfo*> current_active_contents;
1489 if (current_description) {
1490 current_active_contents =
1491 GetActiveContents(*current_description, session_options);
1492 }
1493
1494 StreamParamsVec current_streams =
1495 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001496
zhihuang1c378ed2017-08-17 14:10:50 -07001497 AudioCodecs offer_audio_codecs;
1498 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001499 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001500 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001501 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001502
zhihuang1c378ed2017-08-17 14:10:50 -07001503 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001504 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001505 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001507 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001508 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001509
1510 RtpHeaderExtensions audio_rtp_extensions;
1511 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001512 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1513 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001514
Steve Anton5c72e712018-12-10 14:25:30 -08001515 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001516
zhihuang1c378ed2017-08-17 14:10:50 -07001517 // Iterate through the media description options, matching with existing media
1518 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001519 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001520 for (const MediaDescriptionOptions& media_description_options :
1521 session_options.media_description_options) {
1522 const ContentInfo* current_content = nullptr;
1523 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001524 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001525 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001526 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001527 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001528 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001529 media_description_options.type));
1530 }
1531 switch (media_description_options.type) {
1532 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001533 if (!AddAudioContentForOffer(
1534 media_description_options, session_options, current_content,
1535 current_description, audio_rtp_extensions, offer_audio_codecs,
1536 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001537 return nullptr;
1538 }
1539 break;
1540 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001541 if (!AddVideoContentForOffer(
1542 media_description_options, session_options, current_content,
1543 current_description, video_rtp_extensions, offer_video_codecs,
1544 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001545 return nullptr;
1546 }
1547 break;
1548 case MEDIA_TYPE_DATA:
1549 if (!AddDataContentForOffer(media_description_options, session_options,
1550 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001551 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001552 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001553 return nullptr;
1554 }
1555 break;
1556 default:
1557 RTC_NOTREACHED();
1558 }
1559 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 }
1561
1562 // Bundle the contents together, if we've been asked to do so, and update any
1563 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001564 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001565 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001566 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001567 if (content.rejected) {
1568 continue;
1569 }
zhihuang1c378ed2017-08-17 14:10:50 -07001570 // TODO(deadbeef): There are conditions that make bundling two media
1571 // descriptions together illegal. For example, they use the same payload
1572 // type to represent different codecs, or same IDs for different header
1573 // extensions. We need to detect this and not try to bundle those media
1574 // descriptions together.
1575 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001576 }
Steve Anton2bed3972019-01-04 17:04:30 -08001577 if (!offer_bundle.content_names().empty()) {
1578 offer->AddGroup(offer_bundle);
1579 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1580 RTC_LOG(LS_ERROR)
1581 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1582 return nullptr;
1583 }
1584 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1585 RTC_LOG(LS_ERROR)
1586 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1587 return nullptr;
1588 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589 }
1590 }
Steve Antone831b8c2018-02-01 12:22:16 -08001591
1592 // The following determines how to signal MSIDs to ensure compatibility with
1593 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001594 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001595 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1596 // Plan answerers will look at a=msid and Plan B answerers will look at the
1597 // a=ssrc MSID line.
1598 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1599 cricket::kMsidSignalingSsrcAttribute);
1600 } else {
1601 // Plan B always signals MSID using a=ssrc lines.
1602 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1603 }
1604
Johannes Kron89f874e2018-11-12 10:25:48 +01001605 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1606
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001607 if (session_options.media_transport_settings.has_value()) {
1608 offer->AddMediaTransportSetting(
1609 session_options.media_transport_settings->transport_name,
1610 session_options.media_transport_settings->transport_setting);
1611 }
1612
Steve Anton6fe1fba2018-12-11 10:15:23 -08001613 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614}
1615
Steve Anton6fe1fba2018-12-11 10:15:23 -08001616std::unique_ptr<SessionDescription>
1617MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001618 const SessionDescription* offer,
1619 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001621 if (!offer) {
1622 return nullptr;
1623 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001624
Steve Anton5c72e712018-12-10 14:25:30 -08001625 // Must have options for exactly as many sections as in the offer.
1626 RTC_DCHECK_EQ(offer->contents().size(),
1627 session_options.media_description_options.size());
1628
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001629 IceCredentialsIterator ice_credentials(
1630 session_options.pooled_ice_credentials);
1631
Steve Anton5c72e712018-12-10 14:25:30 -08001632 std::vector<const ContentInfo*> current_active_contents;
1633 if (current_description) {
1634 current_active_contents =
1635 GetActiveContents(*current_description, session_options);
1636 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637
Steve Anton5c72e712018-12-10 14:25:30 -08001638 StreamParamsVec current_streams =
1639 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001640
zhihuang1c378ed2017-08-17 14:10:50 -07001641 // Get list of all possible codecs that respects existing payload type
1642 // mappings and uses a single payload type space.
1643 //
1644 // Note that these lists may be further filtered for each m= section; this
1645 // step is done just to establish the payload type mappings shared by all
1646 // sections.
1647 AudioCodecs answer_audio_codecs;
1648 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001649 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001650 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001651 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001652
1653 if (!session_options.vad_enabled) {
1654 // If application doesn't want CN codecs in answer.
1655 StripCNCodecs(&answer_audio_codecs);
1656 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001657 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001658 session_options.data_channel_type == DCT_SCTP);
1659
Steve Anton5c72e712018-12-10 14:25:30 -08001660 auto answer = absl::make_unique<SessionDescription>();
1661
1662 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1663 // group in the answer with the appropriate content names.
1664 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1665 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1666 // Transport info shared by the bundle group.
1667 std::unique_ptr<TransportInfo> bundle_transport;
1668
1669 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1670
zhihuang1c378ed2017-08-17 14:10:50 -07001671 // Iterate through the media description options, matching with existing
1672 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001673 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001674 for (const MediaDescriptionOptions& media_description_options :
1675 session_options.media_description_options) {
1676 const ContentInfo* offer_content = &offer->contents()[msection_index];
1677 // Media types and MIDs must match between the remote offer and the
1678 // MediaDescriptionOptions.
1679 RTC_DCHECK(
1680 IsMediaContentOfType(offer_content, media_description_options.type));
1681 RTC_DCHECK(media_description_options.mid == offer_content->name);
1682 const ContentInfo* current_content = nullptr;
1683 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001684 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001685 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001686 }
zhihuang1c378ed2017-08-17 14:10:50 -07001687 switch (media_description_options.type) {
1688 case MEDIA_TYPE_AUDIO:
1689 if (!AddAudioContentForAnswer(
1690 media_description_options, session_options, offer_content,
1691 offer, current_content, current_description,
1692 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001693 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001694 return nullptr;
1695 }
1696 break;
1697 case MEDIA_TYPE_VIDEO:
1698 if (!AddVideoContentForAnswer(
1699 media_description_options, session_options, offer_content,
1700 offer, current_content, current_description,
1701 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001702 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001703 return nullptr;
1704 }
1705 break;
1706 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001707 if (!AddDataContentForAnswer(
1708 media_description_options, session_options, offer_content,
1709 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001710 bundle_transport.get(), answer_rtp_data_codecs,
1711 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001712 return nullptr;
1713 }
1714 break;
1715 default:
1716 RTC_NOTREACHED();
1717 }
1718 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001719 // See if we can add the newly generated m= section to the BUNDLE group in
1720 // the answer.
1721 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001722 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001723 offer_bundle->HasContentName(added.name)) {
1724 answer_bundle.AddContentName(added.name);
1725 bundle_transport.reset(
1726 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001728 }
1729
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001730 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1731 // it's empty. RFC5888 says:
1732 //
1733 // A SIP entity that receives an offer that contains an "a=group" line
1734 // with semantics that are understood MUST return an answer that
1735 // contains an "a=group" line with the same semantics.
1736 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001737 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001738 }
deadbeefb7892532017-02-22 19:35:18 -08001739
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001740 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001741 // Share the same ICE credentials and crypto params across all contents,
1742 // as BUNDLE requires.
1743 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001744 RTC_LOG(LS_ERROR)
1745 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001746 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001748
deadbeefb7892532017-02-22 19:35:18 -08001749 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001750 RTC_LOG(LS_ERROR)
1751 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001752 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 }
1754 }
1755
Steve Antone831b8c2018-02-01 12:22:16 -08001756 // The following determines how to signal MSIDs to ensure compatibility with
1757 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001758 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001759 // Unified Plan needs to look at what the offer included to find the most
1760 // compatible answer.
1761 if (offer->msid_signaling() == 0) {
1762 // We end up here in one of three cases:
1763 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1764 // matter what we pick here.
1765 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1766 // it also doesn't matter what we pick here.
1767 // 3. Media that's either sendonly or inactive from the remote endpoint.
1768 // We don't have any information to say whether the endpoint is Plan B
1769 // or Unified Plan, so be conservative and send both.
1770 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1771 cricket::kMsidSignalingSsrcAttribute);
1772 } else if (offer->msid_signaling() ==
1773 (cricket::kMsidSignalingMediaSection |
1774 cricket::kMsidSignalingSsrcAttribute)) {
1775 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1776 // probably talking to a Unified Plan endpoint so respond with just
1777 // a=msid.
1778 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1779 } else {
1780 // Otherwise, it's clear which method the offerer is using so repeat that
1781 // back to them.
1782 answer->set_msid_signaling(offer->msid_signaling());
1783 }
1784 } else {
1785 // Plan B always signals MSID using a=ssrc lines.
1786 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1787 }
1788
Steve Anton6fe1fba2018-12-11 10:15:23 -08001789 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001790}
1791
ossu075af922016-06-14 03:29:38 -07001792const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1793 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001794 switch (direction) {
1795 // If stream is inactive - generate list as if sendrecv.
1796 case RtpTransceiverDirection::kSendRecv:
1797 case RtpTransceiverDirection::kInactive:
1798 return audio_sendrecv_codecs_;
1799 case RtpTransceiverDirection::kSendOnly:
1800 return audio_send_codecs_;
1801 case RtpTransceiverDirection::kRecvOnly:
1802 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001803 }
Steve Anton1d03a752017-11-27 14:30:09 -08001804 RTC_NOTREACHED();
1805 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001806}
1807
1808const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1809 const RtpTransceiverDirection& offer,
1810 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001811 switch (answer) {
1812 // For inactive and sendrecv answers, generate lists as if we were to accept
1813 // the offer's direction. See RFC 3264 Section 6.1.
1814 case RtpTransceiverDirection::kSendRecv:
1815 case RtpTransceiverDirection::kInactive:
1816 return GetAudioCodecsForOffer(
1817 webrtc::RtpTransceiverDirectionReversed(offer));
1818 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001819 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001820 case RtpTransceiverDirection::kRecvOnly:
1821 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001822 }
Steve Anton1d03a752017-11-27 14:30:09 -08001823 RTC_NOTREACHED();
1824 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001825}
1826
Steve Anton5c72e712018-12-10 14:25:30 -08001827void MergeCodecsFromDescription(
1828 const std::vector<const ContentInfo*>& current_active_contents,
1829 AudioCodecs* audio_codecs,
1830 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001831 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001832 UsedPayloadTypes* used_pltypes) {
1833 for (const ContentInfo* content : current_active_contents) {
1834 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001835 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001836 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001837 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001838 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001839 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001840 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001841 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001842 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001843 const RtpDataContentDescription* data =
1844 content->media_description()->as_rtp_data();
1845 if (data) {
1846 // Only relevant for RTP datachannels
1847 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1848 used_pltypes);
1849 }
zhihuang1c378ed2017-08-17 14:10:50 -07001850 }
1851 }
1852}
1853
1854// Getting codecs for an offer involves these steps:
1855//
1856// 1. Construct payload type -> codec mappings for current description.
1857// 2. Add any reference codecs that weren't already present
1858// 3. For each individual media description (m= section), filter codecs based
1859// on the directional attribute (happens in another method).
1860void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001861 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001862 AudioCodecs* audio_codecs,
1863 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001864 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001866 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1867 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001868 UsedPayloadTypes used_pltypes;
1869 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001870 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871
Steve Anton5c72e712018-12-10 14:25:30 -08001872 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001873 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1874 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001875 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001876}
1877
1878// Getting codecs for an answer involves these steps:
1879//
1880// 1. Construct payload type -> codec mappings for current description.
1881// 2. Add any codecs from the offer that weren't already present.
1882// 3. Add any remaining codecs that weren't already present.
1883// 4. For each individual media description (m= section), filter codecs based
1884// on the directional attribute (happens in another method).
1885void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001886 const std::vector<const ContentInfo*>& current_active_contents,
1887 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001888 AudioCodecs* audio_codecs,
1889 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001890 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001891 // First - get all codecs from the current description if the media type
1892 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1893 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001894 UsedPayloadTypes used_pltypes;
1895 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001896 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001897
1898 // Second - filter out codecs that we don't support at all and should ignore.
1899 AudioCodecs filtered_offered_audio_codecs;
1900 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001901 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001902 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001903 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1904 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001905 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001906 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1907 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1908 filtered_offered_audio_codecs,
1909 offered_audio_codec, nullptr) &&
1910 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1911 offered_audio_codec, nullptr)) {
1912 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1913 }
1914 }
1915 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1916 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001917 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001918 for (const VideoCodec& offered_video_codec : video->codecs()) {
1919 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1920 filtered_offered_video_codecs,
1921 offered_video_codec, nullptr) &&
1922 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1923 offered_video_codec, nullptr)) {
1924 filtered_offered_video_codecs.push_back(offered_video_codec);
1925 }
1926 }
1927 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001928 const RtpDataContentDescription* data =
1929 content.media_description()->as_rtp_data();
1930 if (data) {
1931 // RTP data. This part is inactive for SCTP data.
1932 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1933 if (!FindMatchingCodec<RtpDataCodec>(
1934 data->codecs(), filtered_offered_rtp_data_codecs,
1935 offered_rtp_data_codec, nullptr) &&
1936 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1937 offered_rtp_data_codec,
1938 nullptr)) {
1939 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1940 }
zhihuang1c378ed2017-08-17 14:10:50 -07001941 }
1942 }
1943 }
1944 }
1945
Steve Anton5c72e712018-12-10 14:25:30 -08001946 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001947 // |remote_offer|.
1948 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1949 &used_pltypes);
1950 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1951 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001952 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001953 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954}
1955
1956void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001957 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001958 RtpHeaderExtensions* offer_audio_extensions,
1959 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001960 // All header extensions allocated from the same range to avoid potential
1961 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001963 RtpHeaderExtensions all_regular_extensions;
1964 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965
1966 // First - get all extensions from the current description if the media type
1967 // is used.
1968 // Add them to |used_ids| so the local ids are not reused if a new media
1969 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001970 for (const ContentInfo* content : current_active_contents) {
1971 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1972 const AudioContentDescription* audio =
1973 content->media_description()->as_audio();
1974 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1975 &all_regular_extensions, &all_encrypted_extensions,
1976 &used_ids);
1977 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1978 const VideoContentDescription* video =
1979 content->media_description()->as_video();
1980 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1981 &all_regular_extensions, &all_encrypted_extensions,
1982 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983 }
1984 }
1985
Steve Anton5c72e712018-12-10 14:25:30 -08001986 // Add our default RTP header extensions that are not in the current
1987 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001988 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1989 &all_regular_extensions, &all_encrypted_extensions,
1990 &used_ids);
1991 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1992 &all_regular_extensions, &all_encrypted_extensions,
1993 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001994
jbauch5869f502017-06-29 12:31:36 -07001995 // TODO(jbauch): Support adding encrypted header extensions to existing
1996 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001997 if (enable_encrypted_rtp_header_extensions_ &&
1998 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001999 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
2000 &all_encrypted_extensions, &used_ids);
2001 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
2002 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07002003 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004}
2005
2006bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02002007 const std::string& content_name,
2008 const TransportOptions& transport_options,
2009 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002010 SessionDescription* offer_desc,
2011 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02002013 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 const TransportDescription* current_tdesc =
2015 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08002016 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002017 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
2018 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08002019 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002020 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
2021 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022 }
Steve Anton06817cd2018-12-18 15:55:30 -08002023 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
2024 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025}
2026
Steve Anton1a9d3c32018-12-10 17:18:54 -08002027std::unique_ptr<TransportDescription>
2028MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002029 const std::string& content_name,
2030 const SessionDescription* offer_desc,
2031 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002032 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002033 bool require_transport_attributes,
2034 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035 if (!transport_desc_factory_)
2036 return NULL;
2037 const TransportDescription* offer_tdesc =
2038 GetTransportDescription(content_name, offer_desc);
2039 const TransportDescription* current_tdesc =
2040 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08002041 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
2042 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002043 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044}
2045
2046bool MediaSessionDescriptionFactory::AddTransportAnswer(
2047 const std::string& content_name,
2048 const TransportDescription& transport_desc,
2049 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08002050 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051 return true;
2052}
2053
zhihuang1c378ed2017-08-17 14:10:50 -07002054// |audio_codecs| = set of all possible codecs that can be used, with correct
2055// payload type mappings
2056//
2057// |supported_audio_codecs| = set of codecs that are supported for the direction
2058// of this m= section
2059//
2060// acd->codecs() = set of previously negotiated codecs for this m= section
2061//
2062// The payload types should come from audio_codecs, but the order should come
2063// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2064// change existing codec priority, and that new codecs are added with the right
2065// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002066bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002067 const MediaDescriptionOptions& media_description_options,
2068 const MediaSessionOptions& session_options,
2069 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002070 const SessionDescription* current_description,
2071 const RtpHeaderExtensions& audio_rtp_extensions,
2072 const AudioCodecs& audio_codecs,
2073 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002074 SessionDescription* desc,
2075 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002076 // Filter audio_codecs (which includes all codecs, with correctly remapped
2077 // payload types) based on transceiver direction.
2078 const AudioCodecs& supported_audio_codecs =
2079 GetAudioCodecsForOffer(media_description_options.direction);
2080
2081 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002082
2083 if (!media_description_options.codec_preferences.empty()) {
2084 // Add the codecs from the current transceiver's codec preferences.
2085 // They override any existing codecs from previous negotiations.
2086 filtered_codecs = MatchCodecPreference(
2087 media_description_options.codec_preferences, supported_audio_codecs);
2088 } else {
2089 // Add the codecs from current content if it exists and is not rejected nor
2090 // recycled.
2091 if (current_content && !current_content->rejected &&
2092 current_content->name == media_description_options.mid) {
2093 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2094 const AudioContentDescription* acd =
2095 current_content->media_description()->as_audio();
2096 for (const AudioCodec& codec : acd->codecs()) {
2097 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2098 nullptr)) {
2099 filtered_codecs.push_back(codec);
2100 }
zhihuang1c378ed2017-08-17 14:10:50 -07002101 }
2102 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002103 // Add other supported audio codecs.
2104 AudioCodec found_codec;
2105 for (const AudioCodec& codec : supported_audio_codecs) {
2106 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2107 codec, &found_codec) &&
2108 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2109 filtered_codecs, codec, nullptr)) {
2110 // Use the |found_codec| from |audio_codecs| because it has the
2111 // correctly mapped payload type.
2112 filtered_codecs.push_back(found_codec);
2113 }
zhihuang1c378ed2017-08-17 14:10:50 -07002114 }
2115 }
deadbeef44f08192015-12-15 16:20:09 -08002116
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002117 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002118 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2119 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002120
kwiberg31022942016-03-11 14:18:21 -08002121 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002122 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002123 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2124 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002125 if (!CreateMediaContentOffer(media_description_options, session_options,
2126 filtered_codecs, sdes_policy,
2127 GetCryptos(current_content), crypto_suites,
2128 audio_rtp_extensions, ssrc_generator_,
2129 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002130 return false;
2131 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002132
2133 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2134 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002135
Steve Anton4e70a722017-11-28 14:57:10 -08002136 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002137
Steve Anton5adfafd2017-12-20 16:34:00 -08002138 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002139 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002140 if (!AddTransportOffer(media_description_options.mid,
2141 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002142 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002143 return false;
2144 }
2145
2146 return true;
2147}
2148
2149bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002150 const MediaDescriptionOptions& media_description_options,
2151 const MediaSessionOptions& session_options,
2152 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002153 const SessionDescription* current_description,
2154 const RtpHeaderExtensions& video_rtp_extensions,
2155 const VideoCodecs& video_codecs,
2156 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002157 SessionDescription* desc,
2158 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002159 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002160 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2161 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002162
kwiberg31022942016-03-11 14:18:21 -08002163 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002164 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002165 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2166 &crypto_suites);
2167
2168 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002169
2170 if (!media_description_options.codec_preferences.empty()) {
2171 // Add the codecs from the current transceiver's codec preferences.
2172 // They override any existing codecs from previous negotiations.
2173 filtered_codecs = MatchCodecPreference(
2174 media_description_options.codec_preferences, video_codecs_);
2175 } else {
2176 // Add the codecs from current content if it exists and is not rejected nor
2177 // recycled.
2178 if (current_content && !current_content->rejected &&
2179 current_content->name == media_description_options.mid) {
2180 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2181 const VideoContentDescription* vcd =
2182 current_content->media_description()->as_video();
2183 for (const VideoCodec& codec : vcd->codecs()) {
2184 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2185 nullptr)) {
2186 filtered_codecs.push_back(codec);
2187 }
zhihuang1c378ed2017-08-17 14:10:50 -07002188 }
2189 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002190 // Add other supported video codecs.
2191 VideoCodec found_codec;
2192 for (const VideoCodec& codec : video_codecs_) {
2193 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2194 &found_codec) &&
2195 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2196 nullptr)) {
2197 // Use the |found_codec| from |video_codecs| because it has the
2198 // correctly mapped payload type.
2199 filtered_codecs.push_back(found_codec);
2200 }
zhihuang1c378ed2017-08-17 14:10:50 -07002201 }
2202 }
2203
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002204 if (session_options.raw_packetization_for_video) {
2205 for (VideoCodec& codec : filtered_codecs) {
2206 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2207 codec.packetization = kPacketizationParamRaw;
2208 }
2209 }
2210 }
2211
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002212 if (!CreateMediaContentOffer(media_description_options, session_options,
2213 filtered_codecs, sdes_policy,
2214 GetCryptos(current_content), crypto_suites,
2215 video_rtp_extensions, ssrc_generator_,
2216 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002217 return false;
2218 }
2219
zhihuang1c378ed2017-08-17 14:10:50 -07002220 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002221
2222 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2223 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002224
Steve Anton4e70a722017-11-28 14:57:10 -08002225 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002226
Steve Anton5adfafd2017-12-20 16:34:00 -08002227 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002228 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002229 if (!AddTransportOffer(media_description_options.mid,
2230 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002231 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002232 return false;
2233 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002234 return true;
2235}
2236
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002237bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2238 const MediaDescriptionOptions& media_description_options,
2239 const MediaSessionOptions& session_options,
2240 const ContentInfo* current_content,
2241 const SessionDescription* current_description,
2242 StreamParamsVec* current_streams,
2243 SessionDescription* desc,
2244 IceCredentialsIterator* ice_credentials) const {
2245 std::unique_ptr<SctpDataContentDescription> data(
2246 new SctpDataContentDescription());
2247
2248 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2249
2250 cricket::SecurePolicy sdes_policy =
2251 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2252 : secure();
2253 std::vector<std::string> crypto_suites;
2254 // SDES doesn't make sense for SCTP, so we disable it, and we only
2255 // get SDES crypto suites for RTP-based data channels.
2256 sdes_policy = cricket::SEC_DISABLED;
2257 // Unlike SetMediaProtocol below, we need to set the protocol
2258 // before we call CreateMediaContentOffer. Otherwise,
2259 // CreateMediaContentOffer won't know this is SCTP and will
2260 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002261 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002262 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002263 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002264 data->set_max_message_size(kSctpSendBufferSize);
2265
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002266 if (!CreateContentOffer(media_description_options, session_options,
2267 sdes_policy, GetCryptos(current_content),
2268 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2269 current_streams, data.get())) {
2270 return false;
2271 }
2272
2273 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002274 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002275 if (!AddTransportOffer(media_description_options.mid,
2276 media_description_options.transport_options,
2277 current_description, desc, ice_credentials)) {
2278 return false;
2279 }
2280 return true;
2281}
2282
2283bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2284 const MediaDescriptionOptions& media_description_options,
2285 const MediaSessionOptions& session_options,
2286 const ContentInfo* current_content,
2287 const SessionDescription* current_description,
2288 const RtpDataCodecs& rtp_data_codecs,
2289 StreamParamsVec* current_streams,
2290 SessionDescription* desc,
2291 IceCredentialsIterator* ice_credentials) const {
2292 std::unique_ptr<RtpDataContentDescription> data(
2293 new RtpDataContentDescription());
2294 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2295
2296 cricket::SecurePolicy sdes_policy =
2297 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2298 : secure();
2299 std::vector<std::string> crypto_suites;
2300 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2301 &crypto_suites);
2302 if (!CreateMediaContentOffer(media_description_options, session_options,
2303 rtp_data_codecs, sdes_policy,
2304 GetCryptos(current_content), crypto_suites,
2305 RtpHeaderExtensions(), ssrc_generator_,
2306 current_streams, data.get())) {
2307 return false;
2308 }
2309
2310 data->set_bandwidth(kDataMaxBandwidth);
2311 SetMediaProtocol(secure_transport, data.get());
2312 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002313 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002314 if (!AddTransportOffer(media_description_options.mid,
2315 media_description_options.transport_options,
2316 current_description, desc, ice_credentials)) {
2317 return false;
2318 }
2319 return true;
2320}
2321
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002322bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002323 const MediaDescriptionOptions& media_description_options,
2324 const MediaSessionOptions& session_options,
2325 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002326 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002327 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002328 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002329 SessionDescription* desc,
2330 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002331 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2332 // If the DataChannel type is not specified, use the DataChannel type in
2333 // the current description.
2334 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002335 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002336 is_sctp = (current_content->media_description()->protocol() ==
2337 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002338 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002339 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002340 return AddSctpDataContentForOffer(
2341 media_description_options, session_options, current_content,
2342 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002343 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002344 return AddRtpDataContentForOffer(media_description_options, session_options,
2345 current_content, current_description,
2346 rtp_data_codecs, current_streams, desc,
2347 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002348 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002349}
2350
zhihuang1c378ed2017-08-17 14:10:50 -07002351// |audio_codecs| = set of all possible codecs that can be used, with correct
2352// payload type mappings
2353//
2354// |supported_audio_codecs| = set of codecs that are supported for the direction
2355// of this m= section
2356//
2357// acd->codecs() = set of previously negotiated codecs for this m= section
2358//
2359// The payload types should come from audio_codecs, but the order should come
2360// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2361// change existing codec priority, and that new codecs are added with the right
2362// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002363bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002364 const MediaDescriptionOptions& media_description_options,
2365 const MediaSessionOptions& session_options,
2366 const ContentInfo* offer_content,
2367 const SessionDescription* offer_description,
2368 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002369 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002370 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002371 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002372 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002373 SessionDescription* answer,
2374 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002375 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002376 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002377 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002378
Steve Anton1a9d3c32018-12-10 17:18:54 -08002379 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002380 media_description_options.mid, offer_description,
2381 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002382 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002383 if (!audio_transport) {
2384 return false;
2385 }
2386
zhihuang1c378ed2017-08-17 14:10:50 -07002387 // Pick codecs based on the requested communications direction in the offer
2388 // and the selected direction in the answer.
2389 // Note these will be filtered one final time in CreateMediaContentAnswer.
2390 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002391 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002392 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002393 AudioCodecs supported_audio_codecs =
2394 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2395
2396 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002397
2398 if (!media_description_options.codec_preferences.empty()) {
2399 filtered_codecs = MatchCodecPreference(
2400 media_description_options.codec_preferences, supported_audio_codecs);
2401 } else {
2402 // Add the codecs from current content if it exists and is not rejected nor
2403 // recycled.
2404 if (current_content && !current_content->rejected &&
2405 current_content->name == media_description_options.mid) {
2406 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2407 const AudioContentDescription* acd =
2408 current_content->media_description()->as_audio();
2409 for (const AudioCodec& codec : acd->codecs()) {
2410 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2411 nullptr)) {
2412 filtered_codecs.push_back(codec);
2413 }
zhihuang1c378ed2017-08-17 14:10:50 -07002414 }
2415 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002416 // Add other supported audio codecs.
2417 for (const AudioCodec& codec : supported_audio_codecs) {
2418 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2419 codec, nullptr) &&
2420 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2421 filtered_codecs, codec, nullptr)) {
2422 // We should use the local codec with local parameters and the codec id
2423 // would be correctly mapped in |NegotiateCodecs|.
2424 filtered_codecs.push_back(codec);
2425 }
zhihuang1c378ed2017-08-17 14:10:50 -07002426 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002427 }
2428
zhihuang1c378ed2017-08-17 14:10:50 -07002429 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2430 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002431 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002432 new AudioContentDescription());
2433 // Do not require or create SDES cryptos if DTLS is used.
2434 cricket::SecurePolicy sdes_policy =
2435 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002436 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2437 media_description_options, session_options,
2438 ssrc_generator_, current_streams,
2439 audio_answer.get())) {
2440 return false;
2441 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002442 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002443 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002444 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002445 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002446 enable_encrypted_rtp_header_extensions_, current_streams,
2447 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002448 return false; // Fails the session setup.
2449 }
2450
deadbeefb7892532017-02-22 19:35:18 -08002451 bool secure = bundle_transport ? bundle_transport->description.secure()
2452 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002453 bool rejected = media_description_options.stopped ||
2454 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002455 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2456 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002457 if (!AddTransportAnswer(media_description_options.mid,
2458 *(audio_transport.get()), answer)) {
2459 return false;
2460 }
2461
2462 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002463 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2464 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002465 }
2466
zhihuang1c378ed2017-08-17 14:10:50 -07002467 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002468 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002469 return true;
2470}
2471
2472bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002473 const MediaDescriptionOptions& media_description_options,
2474 const MediaSessionOptions& session_options,
2475 const ContentInfo* offer_content,
2476 const SessionDescription* offer_description,
2477 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002478 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002479 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002480 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002481 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002482 SessionDescription* answer,
2483 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002484 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002485 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002486 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002487
Steve Anton1a9d3c32018-12-10 17:18:54 -08002488 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002489 media_description_options.mid, offer_description,
2490 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002491 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002492 if (!video_transport) {
2493 return false;
2494 }
2495
zhihuang1c378ed2017-08-17 14:10:50 -07002496 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002497
2498 if (!media_description_options.codec_preferences.empty()) {
2499 filtered_codecs = MatchCodecPreference(
2500 media_description_options.codec_preferences, video_codecs_);
2501 } else {
2502 // Add the codecs from current content if it exists and is not rejected nor
2503 // recycled.
2504 if (current_content && !current_content->rejected &&
2505 current_content->name == media_description_options.mid) {
2506 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2507 const VideoContentDescription* vcd =
2508 current_content->media_description()->as_video();
2509 for (const VideoCodec& codec : vcd->codecs()) {
2510 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2511 nullptr)) {
2512 filtered_codecs.push_back(codec);
2513 }
zhihuang1c378ed2017-08-17 14:10:50 -07002514 }
2515 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002516 // Add other supported video codecs.
2517 for (const VideoCodec& codec : video_codecs_) {
2518 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2519 nullptr) &&
2520 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2521 nullptr)) {
2522 // We should use the local codec with local parameters and the codec id
2523 // would be correctly mapped in |NegotiateCodecs|.
2524 filtered_codecs.push_back(codec);
2525 }
zhihuang1c378ed2017-08-17 14:10:50 -07002526 }
2527 }
2528
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002529 if (session_options.raw_packetization_for_video) {
2530 for (VideoCodec& codec : filtered_codecs) {
2531 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2532 codec.packetization = kPacketizationParamRaw;
2533 }
2534 }
2535 }
2536
zhihuang1c378ed2017-08-17 14:10:50 -07002537 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2538 session_options.bundle_enabled;
2539
kwiberg31022942016-03-11 14:18:21 -08002540 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002541 new VideoContentDescription());
2542 // Do not require or create SDES cryptos if DTLS is used.
2543 cricket::SecurePolicy sdes_policy =
2544 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002545 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2546 media_description_options, session_options,
2547 ssrc_generator_, current_streams,
2548 video_answer.get())) {
2549 return false;
2550 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002551 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002552 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002553 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002554 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002555 enable_encrypted_rtp_header_extensions_, current_streams,
2556 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002557 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002558 }
deadbeefb7892532017-02-22 19:35:18 -08002559 bool secure = bundle_transport ? bundle_transport->description.secure()
2560 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002561 bool rejected = media_description_options.stopped ||
2562 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002563 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2564 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002565 if (!AddTransportAnswer(media_description_options.mid,
2566 *(video_transport.get()), answer)) {
2567 return false;
2568 }
2569
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002570 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002571 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002572 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002573 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2574 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002575 }
zhihuang1c378ed2017-08-17 14:10:50 -07002576 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002577 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002578 return true;
2579}
2580
2581bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002582 const MediaDescriptionOptions& media_description_options,
2583 const MediaSessionOptions& session_options,
2584 const ContentInfo* offer_content,
2585 const SessionDescription* offer_description,
2586 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002587 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002588 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002589 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002590 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002591 SessionDescription* answer,
2592 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002593 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002594 media_description_options.mid, offer_description,
2595 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002596 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002597 if (!data_transport) {
2598 return false;
2599 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002600
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002601 // Do not require or create SDES cryptos if DTLS is used.
2602 cricket::SecurePolicy sdes_policy =
2603 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002604 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2605 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002606 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002607 std::unique_ptr<MediaContentDescription> data_answer;
2608 if (offer_content->media_description()->as_sctp()) {
2609 // SCTP data content
2610 data_answer = absl::make_unique<SctpDataContentDescription>();
2611 const SctpDataContentDescription* offer_data_description =
2612 offer_content->media_description()->as_sctp();
2613 // Respond with the offerer's proto, whatever it is.
2614 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002615 // Respond with our max message size or the remote max messsage size,
2616 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002617 // 0 is treated specially - it means "I can accept any size". Since
2618 // we do not implement infinite size messages, reply with
2619 // kSctpSendBufferSize.
2620 if (offer_data_description->max_message_size() == 0) {
2621 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2622 } else {
2623 data_answer->as_sctp()->set_max_message_size(std::min(
2624 offer_data_description->max_message_size(), kSctpSendBufferSize));
2625 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002626 if (!CreateMediaContentAnswer(
2627 offer_data_description, media_description_options, session_options,
2628 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2629 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2630 current_streams, bundle_enabled, data_answer.get())) {
2631 return false; // Fails the session setup.
2632 }
2633 // Respond with sctpmap if the offer uses sctpmap.
2634 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2635 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2636 } else {
2637 // RTP offer
2638 data_answer = absl::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002639
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002640 const RtpDataContentDescription* offer_data_description =
2641 offer_content->media_description()->as_rtp_data();
2642 RTC_CHECK(offer_data_description);
2643 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2644 media_description_options, session_options,
2645 ssrc_generator_, current_streams,
2646 data_answer->as_rtp_data())) {
2647 return false;
2648 }
2649 if (!CreateMediaContentAnswer(
2650 offer_data_description, media_description_options, session_options,
2651 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2652 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2653 current_streams, bundle_enabled, data_answer.get())) {
2654 return false; // Fails the session setup.
2655 }
2656 }
Steve Anton46afbf92019-05-10 11:15:18 -07002657
deadbeefb7892532017-02-22 19:35:18 -08002658 bool secure = bundle_transport ? bundle_transport->description.secure()
2659 : data_transport->secure();
2660
zhihuang1c378ed2017-08-17 14:10:50 -07002661 bool rejected = session_options.data_channel_type == DCT_NONE ||
2662 media_description_options.stopped ||
2663 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002664 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2665 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002666 if (!AddTransportAnswer(media_description_options.mid,
2667 *(data_transport.get()), answer)) {
2668 return false;
2669 }
2670
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002671 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002672 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002673 } else {
2674 // RFC 3264
2675 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002676 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002677 }
zhihuang1c378ed2017-08-17 14:10:50 -07002678 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002679 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002680 return true;
2681}
2682
zhihuang1c378ed2017-08-17 14:10:50 -07002683void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2684 audio_sendrecv_codecs_.clear();
2685 all_audio_codecs_.clear();
2686 // Compute the audio codecs union.
2687 for (const AudioCodec& send : audio_send_codecs_) {
2688 all_audio_codecs_.push_back(send);
2689 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2690 send, nullptr)) {
2691 // It doesn't make sense to have an RTX codec we support sending but not
2692 // receiving.
2693 RTC_DCHECK(!IsRtxCodec(send));
2694 }
2695 }
2696 for (const AudioCodec& recv : audio_recv_codecs_) {
2697 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2698 recv, nullptr)) {
2699 all_audio_codecs_.push_back(recv);
2700 }
2701 }
2702 // Use NegotiateCodecs to merge our codec lists, since the operation is
2703 // essentially the same. Put send_codecs as the offered_codecs, which is the
2704 // order we'd like to follow. The reasoning is that encoding is usually more
2705 // expensive than decoding, and prioritizing a codec in the send list probably
2706 // means it's a codec we can handle efficiently.
2707 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002708 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002709}
2710
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002712 return (content && (content->type == MediaProtocolType::kRtp ||
2713 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714}
2715
2716bool IsAudioContent(const ContentInfo* content) {
2717 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2718}
2719
2720bool IsVideoContent(const ContentInfo* content) {
2721 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2722}
2723
2724bool IsDataContent(const ContentInfo* content) {
2725 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2726}
2727
deadbeef0ed85b22016-02-23 17:24:52 -08002728const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2729 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002730 for (const ContentInfo& content : contents) {
2731 if (IsMediaContentOfType(&content, media_type)) {
2732 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733 }
2734 }
deadbeef0ed85b22016-02-23 17:24:52 -08002735 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736}
2737
2738const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2739 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2740}
2741
2742const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2743 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2744}
2745
2746const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2747 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2748}
2749
Steve Antonad7bffc2018-01-22 10:21:56 -08002750const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2751 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002752 if (sdesc == nullptr) {
2753 return nullptr;
2754 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002755
2756 return GetFirstMediaContent(sdesc->contents(), media_type);
2757}
2758
2759const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2760 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2761}
2762
2763const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2764 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2765}
2766
2767const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2768 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2769}
2770
2771const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002772 const SessionDescription* sdesc,
2773 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002775 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776}
2777
2778const AudioContentDescription* GetFirstAudioContentDescription(
2779 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002780 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2781 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002782}
2783
2784const VideoContentDescription* GetFirstVideoContentDescription(
2785 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002786 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2787 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002788}
2789
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002790const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2791 const SessionDescription* sdesc) {
2792 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2793 return desc ? desc->as_rtp_data() : nullptr;
2794}
2795
2796const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2797 const SessionDescription* sdesc) {
2798 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2799 return desc ? desc->as_sctp() : nullptr;
2800}
2801
2802// Returns a shim representing either an SctpDataContentDescription
2803// or an RtpDataContentDescription, as appropriate.
2804// TODO(bugs.webrtc.org/10597): Remove together with shim.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805const DataContentDescription* GetFirstDataContentDescription(
2806 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002807 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2808 return desc ? desc->as_data() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809}
2810
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002811//
2812// Non-const versions of the above functions.
2813//
2814
Steve Anton36b29d12017-10-30 09:57:42 -07002815ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002816 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002817 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002818 if (IsMediaContentOfType(&content, media_type)) {
2819 return &content;
2820 }
2821 }
2822 return nullptr;
2823}
2824
Steve Anton36b29d12017-10-30 09:57:42 -07002825ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002826 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2827}
2828
Steve Anton36b29d12017-10-30 09:57:42 -07002829ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002830 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2831}
2832
Steve Anton36b29d12017-10-30 09:57:42 -07002833ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002834 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2835}
2836
Steve Antonad7bffc2018-01-22 10:21:56 -08002837ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2838 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002839 if (sdesc == nullptr) {
2840 return nullptr;
2841 }
2842
Steve Anton36b29d12017-10-30 09:57:42 -07002843 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002844}
2845
2846ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2847 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2848}
2849
2850ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2851 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2852}
2853
2854ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2855 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2856}
2857
2858MediaContentDescription* GetFirstMediaContentDescription(
2859 SessionDescription* sdesc,
2860 MediaType media_type) {
2861 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002862 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002863}
2864
2865AudioContentDescription* GetFirstAudioContentDescription(
2866 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002867 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2868 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002869}
2870
2871VideoContentDescription* GetFirstVideoContentDescription(
2872 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002873 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2874 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002875}
2876
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002877RtpDataContentDescription* GetFirstRtpDataContentDescription(
2878 SessionDescription* sdesc) {
2879 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2880 return desc ? desc->as_rtp_data() : nullptr;
2881}
2882
2883SctpDataContentDescription* GetFirstSctpDataContentDescription(
2884 SessionDescription* sdesc) {
2885 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2886 return desc ? desc->as_sctp() : nullptr;
2887}
2888
2889// Returns shim
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002890DataContentDescription* GetFirstDataContentDescription(
2891 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002892 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2893 return desc ? desc->as_data() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002894}
2895
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002896} // namespace cricket