blob: 2b7750b58597d7def9de548757ea4f1328bc8ce0 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeef67cf2c12016-04-13 10:07:16 -070013#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve Anton5c72e712018-12-10 14:25:30 -080021#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020022#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020023#include "absl/types/optional.h"
Patrik Höglund7aee3d52017-11-15 13:15:17 +010024#include "api/cryptoparams.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "media/base/h264_profile_level_id.h"
26#include "media/base/mediaconstants.h"
27#include "p2p/base/p2pconstants.h"
28#include "pc/channelmanager.h"
Steve Anton1d03a752017-11-27 14:30:09 -080029#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "pc/srtpfilter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/checks.h"
32#include "rtc_base/helpers.h"
33#include "rtc_base/logging.h"
34#include "rtc_base/stringutils.h"
Artem Titova76af0c2018-07-23 17:38:12 +020035#include "rtc_base/third_party/base64/base64.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
37namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080038
39using webrtc::RtpTransceiverDirection;
40
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080042
Benjamin Wrighta54daf12018-10-11 15:33:17 -070043void GetSupportedSdesCryptoSuiteNames(
44 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
45 const webrtc::CryptoOptions& crypto_options,
46 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080047 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070048 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080049 for (const auto crypto : crypto_suites) {
50 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
51 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080052}
terelius8c011e52016-04-26 05:28:11 -070053} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054
55namespace cricket {
56
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057// RTP Profile names
58// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
59// RFC4585
60const char kMediaProtocolAvpf[] = "RTP/AVPF";
61// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000062const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
63
deadbeeff3938292015-07-15 12:20:53 -070064// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
65// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066const char kMediaProtocolSavpf[] = "RTP/SAVPF";
67
68const char kMediaProtocolRtpPrefix[] = "RTP/";
69
70const char kMediaProtocolSctp[] = "SCTP";
71const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000072const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000073const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074
deadbeef8b7e9ad2017-05-25 09:38:55 -070075// Note that the below functions support some protocol strings purely for
76// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
77// and Interoperability.
78
79static bool IsDtlsRtp(const std::string& protocol) {
80 // Most-likely values first.
81 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
82 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
83}
84
85static bool IsPlainRtp(const std::string& protocol) {
86 // Most-likely values first.
87 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
88 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
89}
90
91static bool IsDtlsSctp(const std::string& protocol) {
92 return protocol == kMediaProtocolDtlsSctp ||
93 protocol == kMediaProtocolUdpDtlsSctp ||
94 protocol == kMediaProtocolTcpDtlsSctp;
95}
96
97static bool IsPlainSctp(const std::string& protocol) {
98 return protocol == kMediaProtocolSctp;
99}
100
101static bool IsSctp(const std::string& protocol) {
102 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
103}
104
Steve Anton1d03a752017-11-27 14:30:09 -0800105static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
106 RtpTransceiverDirection offer,
107 RtpTransceiverDirection wants) {
108 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
109 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
110 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
111 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
112 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
113 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -0700114}
115
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116static bool IsMediaContentOfType(const ContentInfo* content,
117 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800118 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119 return false;
120 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800121 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122}
123
Yves Gerey665174f2018-06-19 15:03:05 +0200124static bool CreateCryptoParams(int tag,
125 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700126 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700127 int key_len;
128 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200129 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
130 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 return false;
132 }
jbauchcb560652016-08-04 05:20:32 -0700133
134 int master_key_len = key_len + salt_len;
135 std::string master_key;
136 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
137 return false;
138 }
139
kwiberg352444f2016-11-28 15:58:53 -0800140 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700141 std::string key = rtc::Base64::Encode(master_key);
142
Steve Anton3a66edf2018-09-10 12:57:37 -0700143 crypto_out->tag = tag;
144 crypto_out->cipher_suite = cipher;
145 crypto_out->key_params = kInline;
146 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147 return true;
148}
149
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700151 CryptoParamsVec* cryptos_out) {
152 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153
Steve Anton3a66edf2018-09-10 12:57:37 -0700154 cryptos_out->resize(size + 1);
155 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156}
157
158void AddMediaCryptos(const CryptoParamsVec& cryptos,
159 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700160 for (const CryptoParams& crypto : cryptos) {
161 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162 }
163}
164
165bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
166 MediaContentDescription* media) {
167 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700168 for (const std::string& crypto_suite : crypto_suites) {
169 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000170 return false;
171 }
172 }
173 AddMediaCryptos(cryptos, media);
174 return true;
175}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176
zhihuang1c378ed2017-08-17 14:10:50 -0700177const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800178 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700179 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800181 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000182}
183
184bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
185 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700186 CryptoParams* crypto_out) {
187 auto it = std::find_if(
188 cryptos.begin(), cryptos.end(),
189 [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
190 if (it == cryptos.end()) {
191 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700193 *crypto_out = *it;
194 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195}
196
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700197// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
198// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700199void GetSupportedAudioSdesCryptoSuites(
200 const webrtc::CryptoOptions& crypto_options,
201 std::vector<int>* crypto_suites) {
202 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700203 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
204 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
205 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700206 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700207 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
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 GetSupportedAudioSdesCryptoSuiteNames(
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(GetSupportedAudioSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedVideoSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227}
228
deadbeef7914b8c2017-04-21 03:23:33 -0700229void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800231 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700232 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
234}
235
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700236void GetSupportedDataSdesCryptoSuites(
237 const webrtc::CryptoOptions& crypto_options,
238 std::vector<int>* crypto_suites) {
239 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700240 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
241 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
242 }
243 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
244}
245
246void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700247 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700248 std::vector<std::string>* crypto_suite_names) {
249 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
250 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800251}
252
jbauchcb560652016-08-04 05:20:32 -0700253// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700254// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
255// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700256// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257static bool SelectCrypto(const MediaContentDescription* offer,
258 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700259 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700260 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
262 const CryptoParamsVec& cryptos = offer->cryptos();
263
Steve Anton3a66edf2018-09-10 12:57:37 -0700264 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700265 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700266 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
267 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
268 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700269 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700270 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 }
272 }
273 return false;
274}
275
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000276// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000277// The generated values are added to |ssrcs|.
278// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000280 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200281 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000282 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200283 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000285 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000286 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
288 ssrcs->push_back(candidate);
289 }
290}
291
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000292// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800293static StreamParamsVec GetCurrentStreamParams(
294 const std::vector<const ContentInfo*>& active_local_contents) {
295 StreamParamsVec stream_params;
296 for (const ContentInfo* content : active_local_contents) {
297 for (const StreamParams& params : content->media_description()->streams()) {
298 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 }
300 }
Steve Anton5c72e712018-12-10 14:25:30 -0800301 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302}
303
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000304// Filters the data codecs for the data channel type.
305void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
306 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700307 const char* codec_name =
308 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700309 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
310 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200311 return absl::EqualsIgnoreCase(codec.name,
312 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700313 }),
314 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000315}
316
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317template <typename IdStruct>
318class UsedIds {
319 public:
320 UsedIds(int min_allowed_id, int max_allowed_id)
321 : min_allowed_id_(min_allowed_id),
322 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200323 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324
325 // Loops through all Id in |ids| and changes its id if it is
326 // already in use by another IdStruct. Call this methods with all Id
327 // in a session description to make sure no duplicate ids exists.
328 // Note that typename Id must be a type of IdStruct.
329 template <typename Id>
330 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700331 for (const Id& id : *ids) {
332 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
334 }
335
336 // Finds and sets an unused id if the |idstruct| id is already in use.
337 void FindAndSetIdUsed(IdStruct* idstruct) {
338 const int original_id = idstruct->id;
339 int new_id = idstruct->id;
340
341 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
342 // If the original id is not in range - this is an id that can't be
343 // dynamically changed.
344 return;
345 }
346
347 if (IsIdUsed(original_id)) {
348 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100349 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
350 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 idstruct->id = new_id;
352 }
353 SetIdUsed(new_id);
354 }
355
356 private:
357 // Returns the first unused id in reverse order.
358 // This hopefully reduce the risk of more collisions. We want to change the
359 // default ids as little as possible.
360 int FindUnusedId() {
361 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
362 --next_id_;
363 }
nisseede5da42017-01-12 05:15:36 -0800364 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 return next_id_;
366 }
367
Yves Gerey665174f2018-06-19 15:03:05 +0200368 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369
Yves Gerey665174f2018-06-19 15:03:05 +0200370 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371
372 const int min_allowed_id_;
373 const int max_allowed_id_;
374 int next_id_;
375 std::set<int> id_set_;
376};
377
378// Helper class used for finding duplicate RTP payload types among audio, video
379// and data codecs. When bundle is used the payload types may not collide.
380class UsedPayloadTypes : public UsedIds<Codec> {
381 public:
382 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200383 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384
385 private:
386 static const int kDynamicPayloadTypeMin = 96;
387 static const int kDynamicPayloadTypeMax = 127;
388};
389
390// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200391// audio and video extensions. Only applies to one-byte header extensions at the
392// moment. ids > 14 will always be reported as available.
393// TODO(kron): This class needs to be refactored when we start to send two-byte
394// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700395class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 public:
397 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200398 : UsedIds<webrtc::RtpExtension>(
399 webrtc::RtpExtension::kMinId,
400 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401
402 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403};
404
zhihuang1c378ed2017-08-17 14:10:50 -0700405// Adds a StreamParams for each SenderOptions in |sender_options| to
406// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000407// |current_params| - All currently known StreamParams of any media type.
408template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700409static bool AddStreamParams(
410 const std::vector<SenderOptions>& sender_options,
411 const std::string& rtcp_cname,
412 StreamParamsVec* current_streams,
413 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700414 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700415 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700416 return true;
417 }
418
Noah Richards2e7a0982015-05-18 14:02:54 -0700419 const bool include_rtx_streams =
420 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421
brandtr03d5fb12016-11-22 03:37:59 -0800422 const bool include_flexfec_stream =
423 ContainsFlexfecCodec(content_description->codecs());
424
zhihuang1c378ed2017-08-17 14:10:50 -0700425 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 // groupid is empty for StreamParams generated using
427 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700428 StreamParams* param =
429 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000430 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700431 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200432 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700433 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700435 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000436 // Add the generated ssrc.
437 for (size_t i = 0; i < ssrcs.size(); ++i) {
438 stream_param.ssrcs.push_back(ssrcs[i]);
439 }
zhihuang1c378ed2017-08-17 14:10:50 -0700440 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000441 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
442 stream_param.ssrc_groups.push_back(group);
443 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700444 // Generate extra ssrcs for include_rtx_streams case.
445 if (include_rtx_streams) {
446 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200447 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700448 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
449 &rtx_ssrcs);
450 for (size_t i = 0; i < ssrcs.size(); ++i) {
451 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
452 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 }
brandtr03d5fb12016-11-22 03:37:59 -0800454 // Generate extra ssrc for include_flexfec_stream case.
455 if (include_flexfec_stream) {
456 // TODO(brandtr): Update when we support multistream protection.
457 if (ssrcs.size() == 1) {
458 std::vector<uint32_t> flexfec_ssrcs;
459 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
460 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
brandtr03d5fb12016-11-22 03:37:59 -0800461 } else if (!ssrcs.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100462 RTC_LOG(LS_WARNING)
brandtr03d5fb12016-11-22 03:37:59 -0800463 << "Our FlexFEC implementation only supports protecting "
Jonas Olsson45cc8902018-02-13 10:37:07 +0100464 "a single media streams. This session has multiple "
465 "media streams however, so no FlexFEC SSRC will be generated.";
brandtr03d5fb12016-11-22 03:37:59 -0800466 }
467 }
zhihuang1c378ed2017-08-17 14:10:50 -0700468 stream_param.cname = rtcp_cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800469 stream_param.set_stream_ids(sender.stream_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 content_description->AddStream(stream_param);
471
472 // Store the new StreamParams in current_streams.
473 // This is necessary so that we can use the CNAME for other media types.
474 current_streams->push_back(stream_param);
475 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700476 // Use existing generated SSRCs/groups, but update the sync_label if
477 // necessary. This may be needed if a MediaStreamTrack was moved from one
478 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800479 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000480 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 }
482 }
483 return true;
484}
485
486// Updates the transport infos of the |sdesc| according to the given
487// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800488// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
489// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
491 SessionDescription* sdesc) {
492 // The bundle should not be empty.
493 if (!sdesc || !bundle_group.FirstContentName()) {
494 return false;
495 }
496
497 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700498 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 const TransportInfo* selected_transport_info =
500 sdesc->GetTransportInfoByName(selected_content_name);
501 if (!selected_transport_info) {
502 return false;
503 }
504
505 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700506 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700508 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800510 ConnectionRole selected_connection_role =
511 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700512 for (TransportInfo& transport_info : sdesc->transport_infos()) {
513 if (bundle_group.HasContentName(transport_info.content_name) &&
514 transport_info.content_name != selected_content_name) {
515 transport_info.description.ice_ufrag = selected_ufrag;
516 transport_info.description.ice_pwd = selected_pwd;
517 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 }
519 }
520 return true;
521}
522
523// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
524// sets it to |cryptos|.
525static bool GetCryptosByName(const SessionDescription* sdesc,
526 const std::string& content_name,
527 CryptoParamsVec* cryptos) {
528 if (!sdesc || !cryptos) {
529 return false;
530 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800532 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 return false;
534 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800535 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 return true;
537}
538
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
540// which are not available in |filter|.
541static void PruneCryptos(const CryptoParamsVec& filter,
542 CryptoParamsVec* target_cryptos) {
543 if (!target_cryptos) {
544 return;
545 }
tzik21995802018-04-26 17:38:28 +0900546
547 target_cryptos->erase(
548 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
549 // Returns true if the |crypto|'s cipher_suite is not
550 // found in |filter|.
551 [&filter](const CryptoParams& crypto) {
552 for (const CryptoParams& entry : filter) {
553 if (entry.cipher_suite == crypto.cipher_suite)
554 return false;
555 }
556 return true;
557 }),
558 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559}
560
Steve Antonfa2260d2017-12-28 16:38:23 -0800561bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800562 return protocol.empty() ||
563 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
564}
565
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566static bool IsRtpContent(SessionDescription* sdesc,
567 const std::string& content_name) {
568 bool is_rtp = false;
569 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800570 if (content && content->media_description()) {
571 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 }
573 return is_rtp;
574}
575
576// Updates the crypto parameters of the |sdesc| according to the given
577// |bundle_group|. The crypto parameters of all the contents within the
578// |bundle_group| should be updated to use the common subset of the
579// available cryptos.
580static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
581 SessionDescription* sdesc) {
582 // The bundle should not be empty.
583 if (!sdesc || !bundle_group.FirstContentName()) {
584 return false;
585 }
586
wu@webrtc.org78187522013-10-07 23:32:02 +0000587 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 // Get the common cryptos.
589 const ContentNames& content_names = bundle_group.content_names();
590 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700591 bool first = true;
592 for (const std::string& content_name : content_names) {
593 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 continue;
595 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000596 // The common cryptos are needed if any of the content does not have DTLS
597 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700598 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000599 common_cryptos_needed = true;
600 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700601 if (first) {
602 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700604 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 return false;
606 }
607 if (common_cryptos.empty()) {
608 // If there's no crypto params, we should just return.
609 return true;
610 }
611 } else {
612 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700613 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 return false;
615 }
616 PruneCryptos(cryptos, &common_cryptos);
617 }
618 }
619
wu@webrtc.org78187522013-10-07 23:32:02 +0000620 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 return false;
622 }
623
624 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700625 for (const std::string& content_name : content_names) {
626 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 continue;
628 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700629 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 if (!media_desc) {
633 return false;
634 }
635 media_desc->set_cryptos(common_cryptos);
636 }
637 }
638 return true;
639}
640
Steve Anton5c72e712018-12-10 14:25:30 -0800641static std::vector<const ContentInfo*> GetActiveContents(
642 const SessionDescription& description,
643 const MediaSessionOptions& session_options) {
644 std::vector<const ContentInfo*> active_contents;
645 for (size_t i = 0; i < description.contents().size(); ++i) {
646 RTC_DCHECK_LT(i, session_options.media_description_options.size());
647 const ContentInfo& content = description.contents()[i];
648 const MediaDescriptionOptions& media_options =
649 session_options.media_description_options[i];
650 if (!content.rejected && !media_options.stopped &&
651 content.name == media_options.mid) {
652 active_contents.push_back(&content);
653 }
654 }
655 return active_contents;
656}
657
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658template <class C>
659static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800660 for (const auto& codec : codecs) {
661 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 return true;
663 }
664 }
665 return false;
666}
667
668template <class C>
669static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200670 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671}
672
brandtr03d5fb12016-11-22 03:37:59 -0800673template <class C>
674static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
675 for (const auto& codec : codecs) {
676 if (IsFlexfecCodec(codec)) {
677 return true;
678 }
679 }
680 return false;
681}
682
683template <class C>
684static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200685 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800686}
687
zhihuang1c378ed2017-08-17 14:10:50 -0700688// Create a media content to be offered for the given |sender_options|,
689// according to the given options.rtcp_mux, session_options.is_muc, codecs,
690// secure_transport, crypto, and current_streams. If we don't currently have
691// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
692// created (according to crypto_suites). The created content is added to the
693// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694template <class C>
695static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700696 const std::vector<SenderOptions>& sender_options,
697 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000699 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 const CryptoParamsVec* current_cryptos,
701 const std::vector<std::string>& crypto_suites,
702 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 StreamParamsVec* current_streams,
704 MediaContentDescriptionImpl<C>* offer) {
705 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706
zhihuang1c378ed2017-08-17 14:10:50 -0700707 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700708 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
709 offer->set_rtcp_reduced_size(true);
710 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 offer->set_rtp_header_extensions(rtp_extensions);
712
zhihuang1c378ed2017-08-17 14:10:50 -0700713 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
714 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715 return false;
716 }
717
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 if (secure_policy != SEC_DISABLED) {
719 if (current_cryptos) {
720 AddMediaCryptos(*current_cryptos, offer);
721 }
722 if (offer->cryptos().empty()) {
723 if (!CreateMediaCryptos(crypto_suites, offer)) {
724 return false;
725 }
726 }
727 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728
deadbeef7af91dd2016-12-13 11:29:11 -0800729 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 return false;
731 }
732 return true;
733}
734
735template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000736static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800737 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000738 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800739 const int codec2_id) {
740 const C* codec1 = FindCodecById(codecs1, codec1_id);
741 const C* codec2 = FindCodecById(codecs2, codec2_id);
742 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000743}
744
745template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746static void NegotiateCodecs(const std::vector<C>& local_codecs,
747 const std::vector<C>& offered_codecs,
748 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800749 for (const C& ours : local_codecs) {
750 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700751 // Note that we intentionally only find one matching codec for each of our
752 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800753 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
754 C negotiated = ours;
755 negotiated.IntersectFeedbackParams(theirs);
756 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800757 const auto apt_it =
758 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800759 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800760 RTC_DCHECK(apt_it != theirs.params.end());
761 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 }
Niels Möller039743e2018-10-23 10:07:25 +0200763 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800764 webrtc::H264::GenerateProfileLevelIdForAnswer(
765 ours.params, theirs.params, &negotiated.params);
766 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800767 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700768 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800769 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 }
771 }
deadbeef67cf2c12016-04-13 10:07:16 -0700772 // RFC3264: Although the answerer MAY list the formats in their desired
773 // order of preference, it is RECOMMENDED that unless there is a
774 // specific reason, the answerer list formats in the same relative order
775 // they were present in the offer.
776 std::unordered_map<int, int> payload_type_preferences;
777 int preference = static_cast<int>(offered_codecs.size() + 1);
778 for (const C& codec : offered_codecs) {
779 payload_type_preferences[codec.id] = preference--;
780 }
781 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
782 [&payload_type_preferences](const C& a, const C& b) {
783 return payload_type_preferences[a.id] >
784 payload_type_preferences[b.id];
785 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786}
787
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800788// Finds a codec in |codecs2| that matches |codec_to_match|, which is
789// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
790// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800792static bool FindMatchingCodec(const std::vector<C>& codecs1,
793 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 const C& codec_to_match,
795 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700796 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
797 // codecs' associated codecs correctly. If not, that's a programming error.
798 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
799 [&codec_to_match](const C& codec) {
800 return &codec == &codec_to_match;
801 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800802 for (const C& potential_match : codecs2) {
803 if (potential_match.Matches(codec_to_match)) {
804 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800805 int apt_value_1 = 0;
806 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800807 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
808 &apt_value_1) ||
809 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
810 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100811 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800812 continue;
813 }
814 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
815 apt_value_2)) {
816 continue;
817 }
818 }
819 if (found_codec) {
820 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 }
822 return true;
823 }
824 }
825 return false;
826}
827
zhihuang1c378ed2017-08-17 14:10:50 -0700828// Find the codec in |codec_list| that |rtx_codec| is associated with.
829template <class C>
830static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
831 const C& rtx_codec) {
832 std::string associated_pt_str;
833 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
834 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100835 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
836 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700837 return nullptr;
838 }
839
840 int associated_pt;
841 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100842 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
843 << " of RTX codec " << rtx_codec.name
844 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700845 return nullptr;
846 }
847
848 // Find the associated reference codec for the reference RTX codec.
849 const C* associated_codec = FindCodecById(codec_list, associated_pt);
850 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100851 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
852 << associated_pt << " for RTX codec " << rtx_codec.name
853 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700854 }
855 return associated_codec;
856}
857
858// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859// already exist in |offered_codecs| and ensure the payload types don't
860// collide.
861template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700862static void MergeCodecs(const std::vector<C>& reference_codecs,
863 std::vector<C>* offered_codecs,
864 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800866 for (const C& reference_codec : reference_codecs) {
867 if (!IsRtxCodec(reference_codec) &&
868 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
869 reference_codec, nullptr)) {
870 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871 used_pltypes->FindAndSetIdUsed(&codec);
872 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 }
874 }
875
876 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800877 for (const C& reference_codec : reference_codecs) {
878 if (IsRtxCodec(reference_codec) &&
879 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
880 reference_codec, nullptr)) {
881 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700882 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700883 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700884 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700885 continue;
886 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800887 // Find a codec in the offered list that matches the reference codec.
888 // Its payload type may be different than the reference codec.
889 C matching_codec;
890 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800891 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100892 RTC_LOG(LS_WARNING)
893 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800894 continue;
895 }
896
897 rtx_codec.params[kCodecParamAssociatedPayloadType] =
898 rtc::ToString(matching_codec.id);
899 used_pltypes->FindAndSetIdUsed(&rtx_codec);
900 offered_codecs->push_back(rtx_codec);
901 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 }
903}
904
zhihuang1c378ed2017-08-17 14:10:50 -0700905static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
906 const webrtc::RtpExtension& ext_to_match,
907 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700908 auto it =
909 std::find_if(extensions.begin(), extensions.end(),
910 [&ext_to_match](const webrtc::RtpExtension& extension) {
911 // We assume that all URIs are given in a canonical
912 // format.
913 return extension.uri == ext_to_match.uri &&
914 extension.encrypt == ext_to_match.encrypt;
915 });
916 if (it == extensions.end()) {
917 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700918 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700919 if (found_extension) {
920 *found_extension = *it;
921 }
922 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700923}
924
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000925static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700926 const webrtc::RtpExtension& ext_to_match,
927 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700928 // We assume that all URIs are given in a canonical format.
929 const webrtc::RtpExtension* found =
930 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
931 ext_to_match.uri);
932 if (!found) {
933 return false;
934 }
935 if (found_extension) {
936 *found_extension = *found;
937 }
938 return true;
939}
940
941static bool FindByUriWithEncryptionPreference(
942 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200943 const webrtc::RtpExtension& ext_to_match,
944 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700945 webrtc::RtpExtension* found_extension) {
946 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700947 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700949 if (extension.uri == ext_to_match.uri) {
950 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700951 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700952 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700953 }
954 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700956 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957 }
958 }
jbauch5869f502017-06-29 12:31:36 -0700959 if (unencrypted_extension) {
960 if (found_extension) {
961 *found_extension = *unencrypted_extension;
962 }
963 return true;
964 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 return false;
966}
967
zhihuang1c378ed2017-08-17 14:10:50 -0700968// Adds all extensions from |reference_extensions| to |offered_extensions| that
969// don't already exist in |offered_extensions| and ensure the IDs don't
970// collide. If an extension is added, it's also added to |regular_extensions| or
971// |encrypted_extensions|, and if the extension is in |regular_extensions| or
972// |encrypted_extensions|, its ID is marked as used in |used_ids|.
973// |offered_extensions| is for either audio or video while |regular_extensions|
974// and |encrypted_extensions| are used for both audio and video. There could be
975// overlap between audio extensions and video extensions.
976static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
977 RtpHeaderExtensions* offered_extensions,
978 RtpHeaderExtensions* regular_extensions,
979 RtpHeaderExtensions* encrypted_extensions,
980 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -0700981 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -0700982 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
983 nullptr)) {
olka3c747662017-08-17 06:50:32 -0700984 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -0700985 if (reference_extension.encrypt) {
986 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
987 &existing)) {
988 offered_extensions->push_back(existing);
989 } else {
990 used_ids->FindAndSetIdUsed(&reference_extension);
991 encrypted_extensions->push_back(reference_extension);
992 offered_extensions->push_back(reference_extension);
993 }
olka3c747662017-08-17 06:50:32 -0700994 } else {
zhihuang1c378ed2017-08-17 14:10:50 -0700995 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
996 &existing)) {
997 offered_extensions->push_back(existing);
998 } else {
999 used_ids->FindAndSetIdUsed(&reference_extension);
1000 regular_extensions->push_back(reference_extension);
1001 offered_extensions->push_back(reference_extension);
1002 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001003 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004 }
1005 }
1006}
1007
jbauch5869f502017-06-29 12:31:36 -07001008static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1009 RtpHeaderExtensions* all_extensions,
1010 UsedRtpHeaderExtensionIds* used_ids) {
1011 RtpHeaderExtensions encrypted_extensions;
1012 for (const webrtc::RtpExtension& extension : *extensions) {
1013 webrtc::RtpExtension existing;
1014 // Don't add encrypted extensions again that were already included in a
1015 // previous offer or regular extensions that are also included as encrypted
1016 // extensions.
1017 if (extension.encrypt ||
1018 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1019 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001020 &existing) &&
1021 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001022 continue;
1023 }
1024
1025 if (FindByUri(*all_extensions, extension, &existing)) {
1026 encrypted_extensions.push_back(existing);
1027 } else {
1028 webrtc::RtpExtension encrypted(extension);
1029 encrypted.encrypt = true;
1030 used_ids->FindAndSetIdUsed(&encrypted);
1031 all_extensions->push_back(encrypted);
1032 encrypted_extensions.push_back(encrypted);
1033 }
1034 }
1035 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001036 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001037}
1038
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039static void NegotiateRtpHeaderExtensions(
1040 const RtpHeaderExtensions& local_extensions,
1041 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001042 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001044 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001045 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001046 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001047 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001048 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 // We respond with their RTP header extension id.
1050 negotiated_extenstions->push_back(theirs);
1051 }
1052 }
1053}
1054
1055static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001056 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1057 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001058 return absl::EqualsIgnoreCase(
1059 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001060 }),
1061 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062}
1063
zhihuang1c378ed2017-08-17 14:10:50 -07001064// Create a media content to be answered for the given |sender_options|
1065// according to the given session_options.rtcp_mux, session_options.streams,
1066// codecs, crypto, and current_streams. If we don't currently have crypto (in
1067// current_cryptos) and it is enabled (in secure_policy), crypto is created
1068// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1069// negotiated with the offer. If the negotiation fails, this method returns
1070// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001071template <class C>
1072static bool CreateMediaContentAnswer(
1073 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001074 const MediaDescriptionOptions& media_description_options,
1075 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001077 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078 const CryptoParamsVec* current_cryptos,
1079 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001080 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 bool bundle_enabled,
1083 MediaContentDescriptionImpl<C>* answer) {
1084 std::vector<C> negotiated_codecs;
1085 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1086 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001087 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001088
Johannes Kron9581bc42018-10-23 10:17:39 +02001089 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001091 NegotiateRtpHeaderExtensions(
1092 local_rtp_extenstions, offer->rtp_header_extensions(),
1093 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1095
zhihuang1c378ed2017-08-17 14:10:50 -07001096 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001097 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1098 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1099 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100
1101 if (sdes_policy != SEC_DISABLED) {
1102 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001103 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1104 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105 if (current_cryptos) {
1106 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1107 }
1108 answer->AddCrypto(crypto);
1109 }
1110 }
1111
deadbeef7af91dd2016-12-13 11:29:11 -08001112 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001113 return false;
1114 }
1115
zhihuang1c378ed2017-08-17 14:10:50 -07001116 if (!AddStreamParams(media_description_options.sender_options,
1117 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118 return false; // Something went seriously wrong.
1119 }
1120
Steve Anton4e70a722017-11-28 14:57:10 -08001121 answer->set_direction(NegotiateRtpTransceiverDirection(
1122 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123 return true;
1124}
1125
1126static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001127 const std::string& protocol,
1128 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001129 // Since not all applications serialize and deserialize the media protocol,
1130 // we will have to accept |protocol| to be empty.
1131 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 return true;
1133 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001134
zhihuangcf5b37c2016-05-05 11:44:35 -07001135 if (type == MEDIA_TYPE_DATA) {
1136 // Check for SCTP, but also for RTP for RTP-based data channels.
1137 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1138 if (secure_transport) {
1139 // Most likely scenarios first.
1140 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1141 IsPlainRtp(protocol);
1142 } else {
1143 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1144 }
1145 }
1146
1147 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1148 // JSEP specifies.
1149 if (secure_transport) {
1150 // Most likely scenarios first.
1151 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1152 } else {
1153 return IsPlainRtp(protocol);
1154 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155}
1156
1157static void SetMediaProtocol(bool secure_transport,
1158 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001159 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001161 else if (secure_transport)
1162 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163 else
1164 desc->set_protocol(kMediaProtocolAvpf);
1165}
1166
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001167// Gets the TransportInfo of the given |content_name| from the
1168// |current_description|. If doesn't exist, returns a new one.
1169static const TransportDescription* GetTransportDescription(
1170 const std::string& content_name,
1171 const SessionDescription* current_description) {
1172 const TransportDescription* desc = NULL;
1173 if (current_description) {
1174 const TransportInfo* info =
1175 current_description->GetTransportInfoByName(content_name);
1176 if (info) {
1177 desc = &info->description;
1178 }
1179 }
1180 return desc;
1181}
1182
1183// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001184static bool IsDtlsActive(const ContentInfo* content,
1185 const SessionDescription* current_description) {
1186 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001187 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001188 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001189
zhihuang1c378ed2017-08-17 14:10:50 -07001190 size_t msection_index = content - &current_description->contents()[0];
1191
1192 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001193 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001194 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001195
zhihuang1c378ed2017-08-17 14:10:50 -07001196 return current_description->transport_infos()[msection_index]
1197 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001198}
1199
Steve Anton8ffb9c32017-08-31 15:45:38 -07001200void MediaDescriptionOptions::AddAudioSender(
1201 const std::string& track_id,
1202 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001203 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001204 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001205}
1206
Steve Anton8ffb9c32017-08-31 15:45:38 -07001207void MediaDescriptionOptions::AddVideoSender(
1208 const std::string& track_id,
1209 const std::vector<std::string>& stream_ids,
1210 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001211 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001212 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001213}
1214
zhihuang1c378ed2017-08-17 14:10:50 -07001215void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1216 const std::string& stream_id) {
1217 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001218 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1219 // than one stream?
1220 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221}
1222
Steve Anton8ffb9c32017-08-31 15:45:38 -07001223void MediaDescriptionOptions::AddSenderInternal(
1224 const std::string& track_id,
1225 const std::vector<std::string>& stream_ids,
1226 int num_sim_layers) {
1227 // TODO(steveanton): Support any number of stream ids.
1228 RTC_CHECK(stream_ids.size() == 1U);
1229 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230}
1231
zhihuang1c378ed2017-08-17 14:10:50 -07001232bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1233 return std::find_if(media_description_options.begin(),
1234 media_description_options.end(),
1235 [type](const MediaDescriptionOptions& t) {
1236 return t.type == type;
1237 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001238}
1239
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1241 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001242 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243
1244MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1245 ChannelManager* channel_manager,
1246 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001247 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001248 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1249 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001251 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001252 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1253 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001254 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001255}
1256
ossudedfd282016-06-14 07:12:39 -07001257const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1258 const {
ossu075af922016-06-14 03:29:38 -07001259 return audio_sendrecv_codecs_;
1260}
1261
1262const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1263 return audio_send_codecs_;
1264}
1265
1266const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1267 return audio_recv_codecs_;
1268}
1269
1270void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001271 const AudioCodecs& send_codecs,
1272 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001273 audio_send_codecs_ = send_codecs;
1274 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001275 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276}
1277
1278SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001279 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001281 // Must have options for each existing section.
1282 if (current_description) {
1283 RTC_DCHECK_LE(current_description->contents().size(),
1284 session_options.media_description_options.size());
1285 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001287 IceCredentialsIterator ice_credentials(
1288 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001289
1290 std::vector<const ContentInfo*> current_active_contents;
1291 if (current_description) {
1292 current_active_contents =
1293 GetActiveContents(*current_description, session_options);
1294 }
1295
1296 StreamParamsVec current_streams =
1297 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298
zhihuang1c378ed2017-08-17 14:10:50 -07001299 AudioCodecs offer_audio_codecs;
1300 VideoCodecs offer_video_codecs;
1301 DataCodecs offer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001302 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001303 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001304
zhihuang1c378ed2017-08-17 14:10:50 -07001305 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001307 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 }
zhihuang1c378ed2017-08-17 14:10:50 -07001309 FilterDataCodecs(&offer_data_codecs,
1310 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311
1312 RtpHeaderExtensions audio_rtp_extensions;
1313 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001314 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1315 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316
Steve Anton5c72e712018-12-10 14:25:30 -08001317 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001318
zhihuang1c378ed2017-08-17 14:10:50 -07001319 // Iterate through the media description options, matching with existing media
1320 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001321 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001322 for (const MediaDescriptionOptions& media_description_options :
1323 session_options.media_description_options) {
1324 const ContentInfo* current_content = nullptr;
1325 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001326 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001327 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001328 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001329 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001330 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001331 media_description_options.type));
1332 }
1333 switch (media_description_options.type) {
1334 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001335 if (!AddAudioContentForOffer(
1336 media_description_options, session_options, current_content,
1337 current_description, audio_rtp_extensions, offer_audio_codecs,
1338 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001339 return nullptr;
1340 }
1341 break;
1342 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001343 if (!AddVideoContentForOffer(
1344 media_description_options, session_options, current_content,
1345 current_description, video_rtp_extensions, offer_video_codecs,
1346 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001347 return nullptr;
1348 }
1349 break;
1350 case MEDIA_TYPE_DATA:
1351 if (!AddDataContentForOffer(media_description_options, session_options,
1352 current_content, current_description,
1353 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001354 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001355 return nullptr;
1356 }
1357 break;
1358 default:
1359 RTC_NOTREACHED();
1360 }
1361 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 }
1363
1364 // Bundle the contents together, if we've been asked to do so, and update any
1365 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001366 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001367 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001368 for (const ContentInfo& content : offer->contents()) {
1369 // TODO(deadbeef): There are conditions that make bundling two media
1370 // descriptions together illegal. For example, they use the same payload
1371 // type to represent different codecs, or same IDs for different header
1372 // extensions. We need to detect this and not try to bundle those media
1373 // descriptions together.
1374 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001375 }
1376 offer->AddGroup(offer_bundle);
1377 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001378 RTC_LOG(LS_ERROR)
1379 << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001380 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001381 }
1382 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001383 RTC_LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001384 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001385 }
1386 }
Steve Antone831b8c2018-02-01 12:22:16 -08001387
1388 // The following determines how to signal MSIDs to ensure compatibility with
1389 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001390 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001391 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1392 // Plan answerers will look at a=msid and Plan B answerers will look at the
1393 // a=ssrc MSID line.
1394 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1395 cricket::kMsidSignalingSsrcAttribute);
1396 } else {
1397 // Plan B always signals MSID using a=ssrc lines.
1398 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1399 }
1400
Johannes Kron89f874e2018-11-12 10:25:48 +01001401 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1402
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403 return offer.release();
1404}
1405
1406SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001407 const SessionDescription* offer,
1408 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001410 if (!offer) {
1411 return nullptr;
1412 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001413
Steve Anton5c72e712018-12-10 14:25:30 -08001414 // Must have options for exactly as many sections as in the offer.
1415 RTC_DCHECK_EQ(offer->contents().size(),
1416 session_options.media_description_options.size());
1417
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001418 IceCredentialsIterator ice_credentials(
1419 session_options.pooled_ice_credentials);
1420
Steve Anton5c72e712018-12-10 14:25:30 -08001421 std::vector<const ContentInfo*> current_active_contents;
1422 if (current_description) {
1423 current_active_contents =
1424 GetActiveContents(*current_description, session_options);
1425 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426
Steve Anton5c72e712018-12-10 14:25:30 -08001427 StreamParamsVec current_streams =
1428 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001429
zhihuang1c378ed2017-08-17 14:10:50 -07001430 // Get list of all possible codecs that respects existing payload type
1431 // mappings and uses a single payload type space.
1432 //
1433 // Note that these lists may be further filtered for each m= section; this
1434 // step is done just to establish the payload type mappings shared by all
1435 // sections.
1436 AudioCodecs answer_audio_codecs;
1437 VideoCodecs answer_video_codecs;
1438 DataCodecs answer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001439 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001440 &answer_video_codecs, &answer_data_codecs);
1441
1442 if (!session_options.vad_enabled) {
1443 // If application doesn't want CN codecs in answer.
1444 StripCNCodecs(&answer_audio_codecs);
1445 }
1446 FilterDataCodecs(&answer_data_codecs,
1447 session_options.data_channel_type == DCT_SCTP);
1448
Steve Anton5c72e712018-12-10 14:25:30 -08001449 auto answer = absl::make_unique<SessionDescription>();
1450
1451 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1452 // group in the answer with the appropriate content names.
1453 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1454 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1455 // Transport info shared by the bundle group.
1456 std::unique_ptr<TransportInfo> bundle_transport;
1457
1458 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1459
zhihuang1c378ed2017-08-17 14:10:50 -07001460 // Iterate through the media description options, matching with existing
1461 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001462 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001463 for (const MediaDescriptionOptions& media_description_options :
1464 session_options.media_description_options) {
1465 const ContentInfo* offer_content = &offer->contents()[msection_index];
1466 // Media types and MIDs must match between the remote offer and the
1467 // MediaDescriptionOptions.
1468 RTC_DCHECK(
1469 IsMediaContentOfType(offer_content, media_description_options.type));
1470 RTC_DCHECK(media_description_options.mid == offer_content->name);
1471 const ContentInfo* current_content = nullptr;
1472 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001473 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001474 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001475 }
zhihuang1c378ed2017-08-17 14:10:50 -07001476 switch (media_description_options.type) {
1477 case MEDIA_TYPE_AUDIO:
1478 if (!AddAudioContentForAnswer(
1479 media_description_options, session_options, offer_content,
1480 offer, current_content, current_description,
1481 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001482 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001483 return nullptr;
1484 }
1485 break;
1486 case MEDIA_TYPE_VIDEO:
1487 if (!AddVideoContentForAnswer(
1488 media_description_options, session_options, offer_content,
1489 offer, current_content, current_description,
1490 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001491 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001492 return nullptr;
1493 }
1494 break;
1495 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001496 if (!AddDataContentForAnswer(
1497 media_description_options, session_options, offer_content,
1498 offer, current_content, current_description,
1499 bundle_transport.get(), answer_data_codecs, &current_streams,
1500 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001501 return nullptr;
1502 }
1503 break;
1504 default:
1505 RTC_NOTREACHED();
1506 }
1507 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001508 // See if we can add the newly generated m= section to the BUNDLE group in
1509 // the answer.
1510 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001511 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001512 offer_bundle->HasContentName(added.name)) {
1513 answer_bundle.AddContentName(added.name);
1514 bundle_transport.reset(
1515 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001516 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001517 }
1518
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001519 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1520 // it's empty. RFC5888 says:
1521 //
1522 // A SIP entity that receives an offer that contains an "a=group" line
1523 // with semantics that are understood MUST return an answer that
1524 // contains an "a=group" line with the same semantics.
1525 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001526 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001527 }
deadbeefb7892532017-02-22 19:35:18 -08001528
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001529 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001530 // Share the same ICE credentials and crypto params across all contents,
1531 // as BUNDLE requires.
1532 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001533 RTC_LOG(LS_ERROR)
1534 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001535 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001536 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537
deadbeefb7892532017-02-22 19:35:18 -08001538 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001539 RTC_LOG(LS_ERROR)
1540 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001541 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542 }
1543 }
1544
Steve Antone831b8c2018-02-01 12:22:16 -08001545 // The following determines how to signal MSIDs to ensure compatibility with
1546 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001547 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001548 // Unified Plan needs to look at what the offer included to find the most
1549 // compatible answer.
1550 if (offer->msid_signaling() == 0) {
1551 // We end up here in one of three cases:
1552 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1553 // matter what we pick here.
1554 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1555 // it also doesn't matter what we pick here.
1556 // 3. Media that's either sendonly or inactive from the remote endpoint.
1557 // We don't have any information to say whether the endpoint is Plan B
1558 // or Unified Plan, so be conservative and send both.
1559 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1560 cricket::kMsidSignalingSsrcAttribute);
1561 } else if (offer->msid_signaling() ==
1562 (cricket::kMsidSignalingMediaSection |
1563 cricket::kMsidSignalingSsrcAttribute)) {
1564 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1565 // probably talking to a Unified Plan endpoint so respond with just
1566 // a=msid.
1567 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1568 } else {
1569 // Otherwise, it's clear which method the offerer is using so repeat that
1570 // back to them.
1571 answer->set_msid_signaling(offer->msid_signaling());
1572 }
1573 } else {
1574 // Plan B always signals MSID using a=ssrc lines.
1575 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1576 }
1577
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 return answer.release();
1579}
1580
ossu075af922016-06-14 03:29:38 -07001581const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1582 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001583 switch (direction) {
1584 // If stream is inactive - generate list as if sendrecv.
1585 case RtpTransceiverDirection::kSendRecv:
1586 case RtpTransceiverDirection::kInactive:
1587 return audio_sendrecv_codecs_;
1588 case RtpTransceiverDirection::kSendOnly:
1589 return audio_send_codecs_;
1590 case RtpTransceiverDirection::kRecvOnly:
1591 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001592 }
Steve Anton1d03a752017-11-27 14:30:09 -08001593 RTC_NOTREACHED();
1594 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001595}
1596
1597const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1598 const RtpTransceiverDirection& offer,
1599 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001600 switch (answer) {
1601 // For inactive and sendrecv answers, generate lists as if we were to accept
1602 // the offer's direction. See RFC 3264 Section 6.1.
1603 case RtpTransceiverDirection::kSendRecv:
1604 case RtpTransceiverDirection::kInactive:
1605 return GetAudioCodecsForOffer(
1606 webrtc::RtpTransceiverDirectionReversed(offer));
1607 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001608 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001609 case RtpTransceiverDirection::kRecvOnly:
1610 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001611 }
Steve Anton1d03a752017-11-27 14:30:09 -08001612 RTC_NOTREACHED();
1613 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001614}
1615
Steve Anton5c72e712018-12-10 14:25:30 -08001616void MergeCodecsFromDescription(
1617 const std::vector<const ContentInfo*>& current_active_contents,
1618 AudioCodecs* audio_codecs,
1619 VideoCodecs* video_codecs,
1620 DataCodecs* data_codecs,
1621 UsedPayloadTypes* used_pltypes) {
1622 for (const ContentInfo* content : current_active_contents) {
1623 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001624 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001625 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001626 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001627 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001628 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001629 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001630 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001631 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001632 const DataContentDescription* data =
Steve Anton5c72e712018-12-10 14:25:30 -08001633 content->media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001634 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1635 }
1636 }
1637}
1638
1639// Getting codecs for an offer involves these steps:
1640//
1641// 1. Construct payload type -> codec mappings for current description.
1642// 2. Add any reference codecs that weren't already present
1643// 3. For each individual media description (m= section), filter codecs based
1644// on the directional attribute (happens in another method).
1645void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001646 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647 AudioCodecs* audio_codecs,
1648 VideoCodecs* video_codecs,
1649 DataCodecs* data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001651 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1652 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001653 UsedPayloadTypes used_pltypes;
1654 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1655 video_codecs, data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656
Steve Anton5c72e712018-12-10 14:25:30 -08001657 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001658 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1659 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1660 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1661}
1662
1663// Getting codecs for an answer involves these steps:
1664//
1665// 1. Construct payload type -> codec mappings for current description.
1666// 2. Add any codecs from the offer that weren't already present.
1667// 3. Add any remaining codecs that weren't already present.
1668// 4. For each individual media description (m= section), filter codecs based
1669// on the directional attribute (happens in another method).
1670void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001671 const std::vector<const ContentInfo*>& current_active_contents,
1672 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001673 AudioCodecs* audio_codecs,
1674 VideoCodecs* video_codecs,
1675 DataCodecs* data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001676 // First - get all codecs from the current description if the media type
1677 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1678 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001679 UsedPayloadTypes used_pltypes;
1680 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1681 video_codecs, data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001682
1683 // Second - filter out codecs that we don't support at all and should ignore.
1684 AudioCodecs filtered_offered_audio_codecs;
1685 VideoCodecs filtered_offered_video_codecs;
1686 DataCodecs filtered_offered_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001687 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001688 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1689 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001690 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001691 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1692 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1693 filtered_offered_audio_codecs,
1694 offered_audio_codec, nullptr) &&
1695 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1696 offered_audio_codec, nullptr)) {
1697 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1698 }
1699 }
1700 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1701 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001702 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001703 for (const VideoCodec& offered_video_codec : video->codecs()) {
1704 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1705 filtered_offered_video_codecs,
1706 offered_video_codec, nullptr) &&
1707 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1708 offered_video_codec, nullptr)) {
1709 filtered_offered_video_codecs.push_back(offered_video_codec);
1710 }
1711 }
1712 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1713 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001714 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001715 for (const DataCodec& offered_data_codec : data->codecs()) {
1716 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1717 filtered_offered_data_codecs,
1718 offered_data_codec, nullptr) &&
1719 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1720 offered_data_codec, nullptr)) {
1721 filtered_offered_data_codecs.push_back(offered_data_codec);
1722 }
1723 }
1724 }
1725 }
1726
Steve Anton5c72e712018-12-10 14:25:30 -08001727 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001728 // |remote_offer|.
1729 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1730 &used_pltypes);
1731 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1732 &used_pltypes);
1733 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1734 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001735}
1736
1737void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001738 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001739 RtpHeaderExtensions* offer_audio_extensions,
1740 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001741 // All header extensions allocated from the same range to avoid potential
1742 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001743 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001744 RtpHeaderExtensions all_regular_extensions;
1745 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001746
1747 // First - get all extensions from the current description if the media type
1748 // is used.
1749 // Add them to |used_ids| so the local ids are not reused if a new media
1750 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001751 for (const ContentInfo* content : current_active_contents) {
1752 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1753 const AudioContentDescription* audio =
1754 content->media_description()->as_audio();
1755 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1756 &all_regular_extensions, &all_encrypted_extensions,
1757 &used_ids);
1758 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1759 const VideoContentDescription* video =
1760 content->media_description()->as_video();
1761 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1762 &all_regular_extensions, &all_encrypted_extensions,
1763 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 }
1765 }
1766
Steve Anton5c72e712018-12-10 14:25:30 -08001767 // Add our default RTP header extensions that are not in the current
1768 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001769 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1770 &all_regular_extensions, &all_encrypted_extensions,
1771 &used_ids);
1772 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1773 &all_regular_extensions, &all_encrypted_extensions,
1774 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001775
jbauch5869f502017-06-29 12:31:36 -07001776 // TODO(jbauch): Support adding encrypted header extensions to existing
1777 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001778 if (enable_encrypted_rtp_header_extensions_ &&
1779 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001780 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1781 &all_encrypted_extensions, &used_ids);
1782 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1783 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001784 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785}
1786
1787bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001788 const std::string& content_name,
1789 const TransportOptions& transport_options,
1790 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001791 SessionDescription* offer_desc,
1792 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001793 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001794 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 const TransportDescription* current_tdesc =
1796 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001797 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001798 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1799 ice_credentials));
Yves Gerey665174f2018-06-19 15:03:05 +02001800 bool ret =
1801 (new_tdesc.get() != NULL &&
1802 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001803 if (!ret) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001804 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1805 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806 }
1807 return ret;
1808}
1809
1810TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1811 const std::string& content_name,
1812 const SessionDescription* offer_desc,
1813 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001814 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001815 bool require_transport_attributes,
1816 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817 if (!transport_desc_factory_)
1818 return NULL;
1819 const TransportDescription* offer_tdesc =
1820 GetTransportDescription(content_name, offer_desc);
1821 const TransportDescription* current_tdesc =
1822 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001823 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1824 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001825 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001826}
1827
1828bool MediaSessionDescriptionFactory::AddTransportAnswer(
1829 const std::string& content_name,
1830 const TransportDescription& transport_desc,
1831 SessionDescription* answer_desc) const {
Yves Gerey665174f2018-06-19 15:03:05 +02001832 if (!answer_desc->AddTransportInfo(
1833 TransportInfo(content_name, transport_desc))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001834 RTC_LOG(LS_ERROR) << "Failed to AddTransportAnswer, content name="
1835 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836 return false;
1837 }
1838 return true;
1839}
1840
zhihuang1c378ed2017-08-17 14:10:50 -07001841// |audio_codecs| = set of all possible codecs that can be used, with correct
1842// payload type mappings
1843//
1844// |supported_audio_codecs| = set of codecs that are supported for the direction
1845// of this m= section
1846//
1847// acd->codecs() = set of previously negotiated codecs for this m= section
1848//
1849// The payload types should come from audio_codecs, but the order should come
1850// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1851// change existing codec priority, and that new codecs are added with the right
1852// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001853bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001854 const MediaDescriptionOptions& media_description_options,
1855 const MediaSessionOptions& session_options,
1856 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001857 const SessionDescription* current_description,
1858 const RtpHeaderExtensions& audio_rtp_extensions,
1859 const AudioCodecs& audio_codecs,
1860 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001861 SessionDescription* desc,
1862 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001863 // Filter audio_codecs (which includes all codecs, with correctly remapped
1864 // payload types) based on transceiver direction.
1865 const AudioCodecs& supported_audio_codecs =
1866 GetAudioCodecsForOffer(media_description_options.direction);
1867
1868 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001869 // Add the codecs from current content if it exists and is not rejected nor
1870 // recycled.
1871 if (current_content && !current_content->rejected &&
1872 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001873 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001874 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001875 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001876 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001877 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1878 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001879 filtered_codecs.push_back(codec);
1880 }
1881 }
1882 }
1883 // Add other supported audio codecs.
1884 AudioCodec found_codec;
1885 for (const AudioCodec& codec : supported_audio_codecs) {
1886 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1887 codec, &found_codec) &&
1888 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1889 codec, nullptr)) {
1890 // Use the |found_codec| from |audio_codecs| because it has the correctly
1891 // mapped payload type.
1892 filtered_codecs.push_back(found_codec);
1893 }
1894 }
deadbeef44f08192015-12-15 16:20:09 -08001895
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001896 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001897 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1898 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001899
kwiberg31022942016-03-11 14:18:21 -08001900 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001901 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001902 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1903 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001904 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001905 media_description_options.sender_options, session_options,
1906 filtered_codecs, sdes_policy, GetCryptos(current_content),
1907 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001908 return false;
1909 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001910
1911 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1912 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001913
Steve Anton4e70a722017-11-28 14:57:10 -08001914 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001915
Steve Anton5adfafd2017-12-20 16:34:00 -08001916 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001917 media_description_options.stopped, audio.release());
1918 if (!AddTransportOffer(media_description_options.mid,
1919 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001920 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001921 return false;
1922 }
1923
1924 return true;
1925}
1926
1927bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001928 const MediaDescriptionOptions& media_description_options,
1929 const MediaSessionOptions& session_options,
1930 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001931 const SessionDescription* current_description,
1932 const RtpHeaderExtensions& video_rtp_extensions,
1933 const VideoCodecs& video_codecs,
1934 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001935 SessionDescription* desc,
1936 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001937 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001938 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1939 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001940
kwiberg31022942016-03-11 14:18:21 -08001941 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001942 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001943 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1944 &crypto_suites);
1945
1946 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001947 // Add the codecs from current content if it exists and is not rejected nor
1948 // recycled.
1949 if (current_content && !current_content->rejected &&
1950 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001951 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07001952 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001953 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001954 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001955 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07001956 nullptr)) {
1957 filtered_codecs.push_back(codec);
1958 }
1959 }
1960 }
1961 // Add other supported video codecs.
1962 VideoCodec found_codec;
1963 for (const VideoCodec& codec : video_codecs_) {
1964 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1965 &found_codec) &&
1966 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1967 nullptr)) {
1968 // Use the |found_codec| from |video_codecs| because it has the correctly
1969 // mapped payload type.
1970 filtered_codecs.push_back(found_codec);
1971 }
1972 }
1973
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001974 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001975 media_description_options.sender_options, session_options,
1976 filtered_codecs, sdes_policy, GetCryptos(current_content),
1977 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001978 return false;
1979 }
1980
zhihuang1c378ed2017-08-17 14:10:50 -07001981 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001982
1983 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1984 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001985
Steve Anton4e70a722017-11-28 14:57:10 -08001986 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001987
Steve Anton5adfafd2017-12-20 16:34:00 -08001988 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001989 media_description_options.stopped, video.release());
1990 if (!AddTransportOffer(media_description_options.mid,
1991 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001992 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001993 return false;
1994 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001995 return true;
1996}
1997
1998bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001999 const MediaDescriptionOptions& media_description_options,
2000 const MediaSessionOptions& session_options,
2001 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002002 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07002003 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002004 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002005 SessionDescription* desc,
2006 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002007 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2008
kwiberg31022942016-03-11 14:18:21 -08002009 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07002010 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2011 // If the DataChannel type is not specified, use the DataChannel type in
2012 // the current description.
2013 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002014 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002015 is_sctp = (current_content->media_description()->protocol() ==
2016 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002017 }
deadbeef44f08192015-12-15 16:20:09 -08002018
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002019 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002020 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2021 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002022 std::vector<std::string> crypto_suites;
2023 if (is_sctp) {
2024 // SDES doesn't make sense for SCTP, so we disable it, and we only
2025 // get SDES crypto suites for RTP-based data channels.
2026 sdes_policy = cricket::SEC_DISABLED;
2027 // Unlike SetMediaProtocol below, we need to set the protocol
2028 // before we call CreateMediaContentOffer. Otherwise,
2029 // CreateMediaContentOffer won't know this is SCTP and will
2030 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002031 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2032 // it's safe to do so. Older versions of webrtc would reject these
2033 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002034 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2035 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002036 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002037 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002038 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002039 }
2040
zhihuang1c378ed2017-08-17 14:10:50 -07002041 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002043 media_description_options.sender_options, session_options,
2044 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2045 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002046 return false;
2047 }
2048
2049 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002050 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002051 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002053 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002054 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002055 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002056 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002057 }
zhihuang1c378ed2017-08-17 14:10:50 -07002058 if (!AddTransportOffer(media_description_options.mid,
2059 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002060 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002061 return false;
2062 }
2063 return true;
2064}
2065
zhihuang1c378ed2017-08-17 14:10:50 -07002066// |audio_codecs| = set of all possible codecs that can be used, with correct
2067// payload type mappings
2068//
2069// |supported_audio_codecs| = set of codecs that are supported for the direction
2070// of this m= section
2071//
2072// acd->codecs() = set of previously negotiated codecs for this m= section
2073//
2074// The payload types should come from audio_codecs, but the order should come
2075// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2076// change existing codec priority, and that new codecs are added with the right
2077// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002078bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002079 const MediaDescriptionOptions& media_description_options,
2080 const MediaSessionOptions& session_options,
2081 const ContentInfo* offer_content,
2082 const SessionDescription* offer_description,
2083 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002084 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002085 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002086 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002087 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002088 SessionDescription* answer,
2089 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002090 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002091 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002092 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002093
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002094 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
2095 media_description_options.mid, offer_description,
2096 media_description_options.transport_options, current_description,
2097 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002098 if (!audio_transport) {
2099 return false;
2100 }
2101
zhihuang1c378ed2017-08-17 14:10:50 -07002102 // Pick codecs based on the requested communications direction in the offer
2103 // and the selected direction in the answer.
2104 // Note these will be filtered one final time in CreateMediaContentAnswer.
2105 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002106 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002107 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002108 AudioCodecs supported_audio_codecs =
2109 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2110
2111 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002112 // Add the codecs from current content if it exists and is not rejected nor
2113 // recycled.
2114 if (current_content && !current_content->rejected &&
2115 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002116 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002117 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002118 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002119 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002120 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2121 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002122 filtered_codecs.push_back(codec);
2123 }
2124 }
2125 }
2126 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002127 for (const AudioCodec& codec : supported_audio_codecs) {
2128 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002129 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002130 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2131 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002132 // We should use the local codec with local parameters and the codec id
2133 // would be correctly mapped in |NegotiateCodecs|.
2134 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002135 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002136 }
2137
zhihuang1c378ed2017-08-17 14:10:50 -07002138 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2139 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002140 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002141 new AudioContentDescription());
2142 // Do not require or create SDES cryptos if DTLS is used.
2143 cricket::SecurePolicy sdes_policy =
2144 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2145 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002146 offer_audio_description, media_description_options, session_options,
2147 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton8f66ddb2018-12-10 16:08:05 -08002148 audio_rtp_header_extensions(),
Steve Anton1b8773d2018-04-06 11:13:34 -07002149 enable_encrypted_rtp_header_extensions_, current_streams,
2150 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002151 return false; // Fails the session setup.
2152 }
2153
deadbeefb7892532017-02-22 19:35:18 -08002154 bool secure = bundle_transport ? bundle_transport->description.secure()
2155 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002156 bool rejected = media_description_options.stopped ||
2157 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002158 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2159 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002160 if (!AddTransportAnswer(media_description_options.mid,
2161 *(audio_transport.get()), answer)) {
2162 return false;
2163 }
2164
2165 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002166 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2167 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002168 }
2169
zhihuang1c378ed2017-08-17 14:10:50 -07002170 answer->AddContent(media_description_options.mid, offer_content->type,
2171 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002172 return true;
2173}
2174
2175bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002176 const MediaDescriptionOptions& media_description_options,
2177 const MediaSessionOptions& session_options,
2178 const ContentInfo* offer_content,
2179 const SessionDescription* offer_description,
2180 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002181 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002182 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002183 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002184 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002185 SessionDescription* answer,
2186 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002187 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002188 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002189 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002190
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002191 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer(
2192 media_description_options.mid, offer_description,
2193 media_description_options.transport_options, current_description,
2194 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002195 if (!video_transport) {
2196 return false;
2197 }
2198
zhihuang1c378ed2017-08-17 14:10:50 -07002199 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002200 // Add the codecs from current content if it exists and is not rejected nor
2201 // recycled.
2202 if (current_content && !current_content->rejected &&
2203 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002204 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002205 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002206 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002207 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002208 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002209 nullptr)) {
2210 filtered_codecs.push_back(codec);
2211 }
2212 }
2213 }
2214 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002215 for (const VideoCodec& codec : video_codecs_) {
2216 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002217 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002218 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2219 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002220 // We should use the local codec with local parameters and the codec id
2221 // would be correctly mapped in |NegotiateCodecs|.
2222 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002223 }
2224 }
2225
2226 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2227 session_options.bundle_enabled;
2228
kwiberg31022942016-03-11 14:18:21 -08002229 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002230 new VideoContentDescription());
2231 // Do not require or create SDES cryptos if DTLS is used.
2232 cricket::SecurePolicy sdes_policy =
2233 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002234 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002235 offer_video_description, media_description_options, session_options,
2236 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton8f66ddb2018-12-10 16:08:05 -08002237 video_rtp_header_extensions(),
Steve Anton1b8773d2018-04-06 11:13:34 -07002238 enable_encrypted_rtp_header_extensions_, current_streams,
2239 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002240 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002241 }
deadbeefb7892532017-02-22 19:35:18 -08002242 bool secure = bundle_transport ? bundle_transport->description.secure()
2243 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002244 bool rejected = media_description_options.stopped ||
2245 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002246 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2247 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002248 if (!AddTransportAnswer(media_description_options.mid,
2249 *(video_transport.get()), answer)) {
2250 return false;
2251 }
2252
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002253 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002254 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002255 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002256 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2257 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002258 }
zhihuang1c378ed2017-08-17 14:10:50 -07002259 answer->AddContent(media_description_options.mid, offer_content->type,
2260 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002261 return true;
2262}
2263
2264bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002265 const MediaDescriptionOptions& media_description_options,
2266 const MediaSessionOptions& session_options,
2267 const ContentInfo* offer_content,
2268 const SessionDescription* offer_description,
2269 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002270 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002271 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002272 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002274 SessionDescription* answer,
2275 IceCredentialsIterator* ice_credentials) const {
2276 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer(
2277 media_description_options.mid, offer_description,
2278 media_description_options.transport_options, current_description,
2279 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002280 if (!data_transport) {
2281 return false;
2282 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002283
kwiberg31022942016-03-11 14:18:21 -08002284 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002285 new DataContentDescription());
2286 // Do not require or create SDES cryptos if DTLS is used.
2287 cricket::SecurePolicy sdes_policy =
2288 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002289 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2290 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002291 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2292 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002293 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002294 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002295 offer_data_description, media_description_options, session_options,
2296 data_codecs, sdes_policy, GetCryptos(current_content),
2297 RtpHeaderExtensions(), enable_encrypted_rtp_header_extensions_,
2298 current_streams, bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002299 return false; // Fails the session setup.
2300 }
2301
zstein4b2e0822017-02-17 19:48:38 -08002302 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002303 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2304 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2305
deadbeefb7892532017-02-22 19:35:18 -08002306 bool secure = bundle_transport ? bundle_transport->description.secure()
2307 : data_transport->secure();
2308
zhihuang1c378ed2017-08-17 14:10:50 -07002309 bool rejected = session_options.data_channel_type == DCT_NONE ||
2310 media_description_options.stopped ||
2311 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002312 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2313 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002314 if (!AddTransportAnswer(media_description_options.mid,
2315 *(data_transport.get()), answer)) {
2316 return false;
2317 }
2318
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002319 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002320 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002321 } else {
2322 // RFC 3264
2323 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002324 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002325 }
zhihuang1c378ed2017-08-17 14:10:50 -07002326 answer->AddContent(media_description_options.mid, offer_content->type,
2327 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002328 return true;
2329}
2330
zhihuang1c378ed2017-08-17 14:10:50 -07002331void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2332 audio_sendrecv_codecs_.clear();
2333 all_audio_codecs_.clear();
2334 // Compute the audio codecs union.
2335 for (const AudioCodec& send : audio_send_codecs_) {
2336 all_audio_codecs_.push_back(send);
2337 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2338 send, nullptr)) {
2339 // It doesn't make sense to have an RTX codec we support sending but not
2340 // receiving.
2341 RTC_DCHECK(!IsRtxCodec(send));
2342 }
2343 }
2344 for (const AudioCodec& recv : audio_recv_codecs_) {
2345 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2346 recv, nullptr)) {
2347 all_audio_codecs_.push_back(recv);
2348 }
2349 }
2350 // Use NegotiateCodecs to merge our codec lists, since the operation is
2351 // essentially the same. Put send_codecs as the offered_codecs, which is the
2352 // order we'd like to follow. The reasoning is that encoding is usually more
2353 // expensive than decoding, and prioritizing a codec in the send list probably
2354 // means it's a codec we can handle efficiently.
2355 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2356 &audio_sendrecv_codecs_);
2357}
2358
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002359bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002360 return (content && (content->type == MediaProtocolType::kRtp ||
2361 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362}
2363
2364bool IsAudioContent(const ContentInfo* content) {
2365 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2366}
2367
2368bool IsVideoContent(const ContentInfo* content) {
2369 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2370}
2371
2372bool IsDataContent(const ContentInfo* content) {
2373 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2374}
2375
deadbeef0ed85b22016-02-23 17:24:52 -08002376const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2377 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002378 for (const ContentInfo& content : contents) {
2379 if (IsMediaContentOfType(&content, media_type)) {
2380 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381 }
2382 }
deadbeef0ed85b22016-02-23 17:24:52 -08002383 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384}
2385
2386const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2387 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2388}
2389
2390const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2391 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2392}
2393
2394const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2395 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2396}
2397
Steve Antonad7bffc2018-01-22 10:21:56 -08002398const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2399 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002400 if (sdesc == nullptr) {
2401 return nullptr;
2402 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002403
2404 return GetFirstMediaContent(sdesc->contents(), media_type);
2405}
2406
2407const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2408 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2409}
2410
2411const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2412 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2413}
2414
2415const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2416 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2417}
2418
2419const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002420 const SessionDescription* sdesc,
2421 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002422 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002423 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002424}
2425
2426const AudioContentDescription* GetFirstAudioContentDescription(
2427 const SessionDescription* sdesc) {
2428 return static_cast<const AudioContentDescription*>(
2429 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2430}
2431
2432const VideoContentDescription* GetFirstVideoContentDescription(
2433 const SessionDescription* sdesc) {
2434 return static_cast<const VideoContentDescription*>(
2435 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2436}
2437
2438const DataContentDescription* GetFirstDataContentDescription(
2439 const SessionDescription* sdesc) {
2440 return static_cast<const DataContentDescription*>(
2441 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2442}
2443
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002444//
2445// Non-const versions of the above functions.
2446//
2447
Steve Anton36b29d12017-10-30 09:57:42 -07002448ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002449 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002450 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002451 if (IsMediaContentOfType(&content, media_type)) {
2452 return &content;
2453 }
2454 }
2455 return nullptr;
2456}
2457
Steve Anton36b29d12017-10-30 09:57:42 -07002458ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002459 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2460}
2461
Steve Anton36b29d12017-10-30 09:57:42 -07002462ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002463 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2464}
2465
Steve Anton36b29d12017-10-30 09:57:42 -07002466ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002467 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2468}
2469
Steve Antonad7bffc2018-01-22 10:21:56 -08002470ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2471 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002472 if (sdesc == nullptr) {
2473 return nullptr;
2474 }
2475
Steve Anton36b29d12017-10-30 09:57:42 -07002476 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002477}
2478
2479ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2480 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2481}
2482
2483ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2484 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2485}
2486
2487ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2488 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2489}
2490
2491MediaContentDescription* GetFirstMediaContentDescription(
2492 SessionDescription* sdesc,
2493 MediaType media_type) {
2494 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002495 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002496}
2497
2498AudioContentDescription* GetFirstAudioContentDescription(
2499 SessionDescription* sdesc) {
2500 return static_cast<AudioContentDescription*>(
2501 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2502}
2503
2504VideoContentDescription* GetFirstVideoContentDescription(
2505 SessionDescription* sdesc) {
2506 return static_cast<VideoContentDescription*>(
2507 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2508}
2509
2510DataContentDescription* GetFirstDataContentDescription(
2511 SessionDescription* sdesc) {
2512 return static_cast<DataContentDescription*>(
2513 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2514}
2515
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516} // namespace cricket