blob: 4898ed9f03feb82e2569a70d031b401c0eb24711 [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"
Artem Titova76af0c2018-07-23 17:38:12 +020034#include "rtc_base/third_party/base64/base64.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
36namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080037
38using webrtc::RtpTransceiverDirection;
39
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080041
Benjamin Wrighta54daf12018-10-11 15:33:17 -070042void GetSupportedSdesCryptoSuiteNames(
43 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
44 const webrtc::CryptoOptions& crypto_options,
45 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070047 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080048 for (const auto crypto : crypto_suites) {
49 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
50 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051}
terelius8c011e52016-04-26 05:28:11 -070052} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053
54namespace cricket {
55
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056// RTP Profile names
57// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
58// RFC4585
59const char kMediaProtocolAvpf[] = "RTP/AVPF";
60// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000061const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
62
deadbeeff3938292015-07-15 12:20:53 -070063// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
64// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065const char kMediaProtocolSavpf[] = "RTP/SAVPF";
66
67const char kMediaProtocolRtpPrefix[] = "RTP/";
68
69const char kMediaProtocolSctp[] = "SCTP";
70const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000071const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000072const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
deadbeef8b7e9ad2017-05-25 09:38:55 -070074// Note that the below functions support some protocol strings purely for
75// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
76// and Interoperability.
77
78static bool IsDtlsRtp(const std::string& protocol) {
79 // Most-likely values first.
80 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
81 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
82}
83
84static bool IsPlainRtp(const std::string& protocol) {
85 // Most-likely values first.
86 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
87 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
88}
89
90static bool IsDtlsSctp(const std::string& protocol) {
91 return protocol == kMediaProtocolDtlsSctp ||
92 protocol == kMediaProtocolUdpDtlsSctp ||
93 protocol == kMediaProtocolTcpDtlsSctp;
94}
95
96static bool IsPlainSctp(const std::string& protocol) {
97 return protocol == kMediaProtocolSctp;
98}
99
100static bool IsSctp(const std::string& protocol) {
101 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
102}
103
Steve Anton1d03a752017-11-27 14:30:09 -0800104static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
105 RtpTransceiverDirection offer,
106 RtpTransceiverDirection wants) {
107 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
108 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
109 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
110 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
111 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
112 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -0700113}
114
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115static bool IsMediaContentOfType(const ContentInfo* content,
116 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800117 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118 return false;
119 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800120 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121}
122
Yves Gerey665174f2018-06-19 15:03:05 +0200123static bool CreateCryptoParams(int tag,
124 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700125 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700126 int key_len;
127 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200128 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
129 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 return false;
131 }
jbauchcb560652016-08-04 05:20:32 -0700132
133 int master_key_len = key_len + salt_len;
134 std::string master_key;
135 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
136 return false;
137 }
138
kwiberg352444f2016-11-28 15:58:53 -0800139 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700140 std::string key = rtc::Base64::Encode(master_key);
141
Steve Anton3a66edf2018-09-10 12:57:37 -0700142 crypto_out->tag = tag;
143 crypto_out->cipher_suite = cipher;
144 crypto_out->key_params = kInline;
145 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 return true;
147}
148
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700150 CryptoParamsVec* cryptos_out) {
151 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152
Steve Anton3a66edf2018-09-10 12:57:37 -0700153 cryptos_out->resize(size + 1);
154 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155}
156
157void AddMediaCryptos(const CryptoParamsVec& cryptos,
158 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700159 for (const CryptoParams& crypto : cryptos) {
160 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161 }
162}
163
164bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
165 MediaContentDescription* media) {
166 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700167 for (const std::string& crypto_suite : crypto_suites) {
168 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000169 return false;
170 }
171 }
172 AddMediaCryptos(cryptos, media);
173 return true;
174}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175
zhihuang1c378ed2017-08-17 14:10:50 -0700176const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800177 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700178 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800180 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000181}
182
183bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
184 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700185 CryptoParams* crypto_out) {
186 auto it = std::find_if(
187 cryptos.begin(), cryptos.end(),
188 [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
189 if (it == cryptos.end()) {
190 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000191 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700192 *crypto_out = *it;
193 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000194}
195
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700196// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
197// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700198void GetSupportedAudioSdesCryptoSuites(
199 const webrtc::CryptoOptions& crypto_options,
200 std::vector<int>* crypto_suites) {
201 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700202 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
203 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
204 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700205 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700206 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
207 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800208 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209}
210
deadbeef7914b8c2017-04-21 03:23:33 -0700211void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700212 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800213 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700214 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
215 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216}
217
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700218void GetSupportedVideoSdesCryptoSuites(
219 const webrtc::CryptoOptions& crypto_options,
220 std::vector<int>* crypto_suites) {
221 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700222 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
224 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800225 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226}
227
deadbeef7914b8c2017-04-21 03:23:33 -0700228void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700229 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800230 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700231 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
232 crypto_options, crypto_suite_names);
233}
234
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700235void GetSupportedDataSdesCryptoSuites(
236 const webrtc::CryptoOptions& crypto_options,
237 std::vector<int>* crypto_suites) {
238 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700239 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
240 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
241 }
242 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
243}
244
245void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700246 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700247 std::vector<std::string>* crypto_suite_names) {
248 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
249 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800250}
251
jbauchcb560652016-08-04 05:20:32 -0700252// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700253// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
254// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700255// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256static bool SelectCrypto(const MediaContentDescription* offer,
257 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700258 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700259 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
261 const CryptoParamsVec& cryptos = offer->cryptos();
262
Steve Anton3a66edf2018-09-10 12:57:37 -0700263 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700264 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700265 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
266 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
267 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700268 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700269 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 }
271 }
272 return false;
273}
274
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000276// The generated values are added to |ssrcs|.
277// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000279 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200280 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000281 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200282 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000284 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000285 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
287 ssrcs->push_back(candidate);
288 }
289}
290
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800292static StreamParamsVec GetCurrentStreamParams(
293 const std::vector<const ContentInfo*>& active_local_contents) {
294 StreamParamsVec stream_params;
295 for (const ContentInfo* content : active_local_contents) {
296 for (const StreamParams& params : content->media_description()->streams()) {
297 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 }
299 }
Steve Anton5c72e712018-12-10 14:25:30 -0800300 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301}
302
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000303// Filters the data codecs for the data channel type.
304void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
305 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700306 const char* codec_name =
307 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700308 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
309 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200310 return absl::EqualsIgnoreCase(codec.name,
311 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700312 }),
313 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000314}
315
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000316template <typename IdStruct>
317class UsedIds {
318 public:
319 UsedIds(int min_allowed_id, int max_allowed_id)
320 : min_allowed_id_(min_allowed_id),
321 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200322 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000323
324 // Loops through all Id in |ids| and changes its id if it is
325 // already in use by another IdStruct. Call this methods with all Id
326 // in a session description to make sure no duplicate ids exists.
327 // Note that typename Id must be a type of IdStruct.
328 template <typename Id>
329 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700330 for (const Id& id : *ids) {
331 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 }
333 }
334
335 // Finds and sets an unused id if the |idstruct| id is already in use.
336 void FindAndSetIdUsed(IdStruct* idstruct) {
337 const int original_id = idstruct->id;
338 int new_id = idstruct->id;
339
340 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
341 // If the original id is not in range - this is an id that can't be
342 // dynamically changed.
343 return;
344 }
345
346 if (IsIdUsed(original_id)) {
347 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100348 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
349 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 idstruct->id = new_id;
351 }
352 SetIdUsed(new_id);
353 }
354
355 private:
356 // Returns the first unused id in reverse order.
357 // This hopefully reduce the risk of more collisions. We want to change the
358 // default ids as little as possible.
359 int FindUnusedId() {
360 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
361 --next_id_;
362 }
nisseede5da42017-01-12 05:15:36 -0800363 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 return next_id_;
365 }
366
Yves Gerey665174f2018-06-19 15:03:05 +0200367 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368
Yves Gerey665174f2018-06-19 15:03:05 +0200369 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370
371 const int min_allowed_id_;
372 const int max_allowed_id_;
373 int next_id_;
374 std::set<int> id_set_;
375};
376
377// Helper class used for finding duplicate RTP payload types among audio, video
378// and data codecs. When bundle is used the payload types may not collide.
379class UsedPayloadTypes : public UsedIds<Codec> {
380 public:
381 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200382 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383
384 private:
385 static const int kDynamicPayloadTypeMin = 96;
386 static const int kDynamicPayloadTypeMax = 127;
387};
388
389// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200390// audio and video extensions. Only applies to one-byte header extensions at the
391// moment. ids > 14 will always be reported as available.
392// TODO(kron): This class needs to be refactored when we start to send two-byte
393// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700394class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395 public:
396 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200397 : UsedIds<webrtc::RtpExtension>(
398 webrtc::RtpExtension::kMinId,
399 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400
401 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402};
403
zhihuang1c378ed2017-08-17 14:10:50 -0700404// Adds a StreamParams for each SenderOptions in |sender_options| to
405// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406// |current_params| - All currently known StreamParams of any media type.
407template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700408static bool AddStreamParams(
409 const std::vector<SenderOptions>& sender_options,
410 const std::string& rtcp_cname,
411 StreamParamsVec* current_streams,
412 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700413 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700414 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700415 return true;
416 }
417
Noah Richards2e7a0982015-05-18 14:02:54 -0700418 const bool include_rtx_streams =
419 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420
brandtr03d5fb12016-11-22 03:37:59 -0800421 const bool include_flexfec_stream =
422 ContainsFlexfecCodec(content_description->codecs());
423
zhihuang1c378ed2017-08-17 14:10:50 -0700424 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 // groupid is empty for StreamParams generated using
426 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700427 StreamParams* param =
428 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000429 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700430 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200431 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700432 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700434 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000435 // Add the generated ssrc.
436 for (size_t i = 0; i < ssrcs.size(); ++i) {
437 stream_param.ssrcs.push_back(ssrcs[i]);
438 }
zhihuang1c378ed2017-08-17 14:10:50 -0700439 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000440 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
441 stream_param.ssrc_groups.push_back(group);
442 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700443 // Generate extra ssrcs for include_rtx_streams case.
444 if (include_rtx_streams) {
445 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200446 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700447 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
448 &rtx_ssrcs);
449 for (size_t i = 0; i < ssrcs.size(); ++i) {
450 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
451 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 }
brandtr03d5fb12016-11-22 03:37:59 -0800453 // Generate extra ssrc for include_flexfec_stream case.
454 if (include_flexfec_stream) {
455 // TODO(brandtr): Update when we support multistream protection.
456 if (ssrcs.size() == 1) {
457 std::vector<uint32_t> flexfec_ssrcs;
458 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
459 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
brandtr03d5fb12016-11-22 03:37:59 -0800460 } else if (!ssrcs.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100461 RTC_LOG(LS_WARNING)
brandtr03d5fb12016-11-22 03:37:59 -0800462 << "Our FlexFEC implementation only supports protecting "
Jonas Olsson45cc8902018-02-13 10:37:07 +0100463 "a single media streams. This session has multiple "
464 "media streams however, so no FlexFEC SSRC will be generated.";
brandtr03d5fb12016-11-22 03:37:59 -0800465 }
466 }
zhihuang1c378ed2017-08-17 14:10:50 -0700467 stream_param.cname = rtcp_cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800468 stream_param.set_stream_ids(sender.stream_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 content_description->AddStream(stream_param);
470
471 // Store the new StreamParams in current_streams.
472 // This is necessary so that we can use the CNAME for other media types.
473 current_streams->push_back(stream_param);
474 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700475 // Use existing generated SSRCs/groups, but update the sync_label if
476 // necessary. This may be needed if a MediaStreamTrack was moved from one
477 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800478 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000479 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480 }
481 }
482 return true;
483}
484
485// Updates the transport infos of the |sdesc| according to the given
486// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800487// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
488// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
490 SessionDescription* sdesc) {
491 // The bundle should not be empty.
492 if (!sdesc || !bundle_group.FirstContentName()) {
493 return false;
494 }
495
496 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700497 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 const TransportInfo* selected_transport_info =
499 sdesc->GetTransportInfoByName(selected_content_name);
500 if (!selected_transport_info) {
501 return false;
502 }
503
504 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700505 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700507 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800509 ConnectionRole selected_connection_role =
510 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700511 for (TransportInfo& transport_info : sdesc->transport_infos()) {
512 if (bundle_group.HasContentName(transport_info.content_name) &&
513 transport_info.content_name != selected_content_name) {
514 transport_info.description.ice_ufrag = selected_ufrag;
515 transport_info.description.ice_pwd = selected_pwd;
516 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 }
518 }
519 return true;
520}
521
522// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
523// sets it to |cryptos|.
524static bool GetCryptosByName(const SessionDescription* sdesc,
525 const std::string& content_name,
526 CryptoParamsVec* cryptos) {
527 if (!sdesc || !cryptos) {
528 return false;
529 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800531 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 return false;
533 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800534 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 return true;
536}
537
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
539// which are not available in |filter|.
540static void PruneCryptos(const CryptoParamsVec& filter,
541 CryptoParamsVec* target_cryptos) {
542 if (!target_cryptos) {
543 return;
544 }
tzik21995802018-04-26 17:38:28 +0900545
546 target_cryptos->erase(
547 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
548 // Returns true if the |crypto|'s cipher_suite is not
549 // found in |filter|.
550 [&filter](const CryptoParams& crypto) {
551 for (const CryptoParams& entry : filter) {
552 if (entry.cipher_suite == crypto.cipher_suite)
553 return false;
554 }
555 return true;
556 }),
557 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558}
559
Steve Antonfa2260d2017-12-28 16:38:23 -0800560bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800561 return protocol.empty() ||
562 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
563}
564
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565static bool IsRtpContent(SessionDescription* sdesc,
566 const std::string& content_name) {
567 bool is_rtp = false;
568 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800569 if (content && content->media_description()) {
570 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 }
572 return is_rtp;
573}
574
575// Updates the crypto parameters of the |sdesc| according to the given
576// |bundle_group|. The crypto parameters of all the contents within the
577// |bundle_group| should be updated to use the common subset of the
578// available cryptos.
579static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
580 SessionDescription* sdesc) {
581 // The bundle should not be empty.
582 if (!sdesc || !bundle_group.FirstContentName()) {
583 return false;
584 }
585
wu@webrtc.org78187522013-10-07 23:32:02 +0000586 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 // Get the common cryptos.
588 const ContentNames& content_names = bundle_group.content_names();
589 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700590 bool first = true;
591 for (const std::string& content_name : content_names) {
592 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 continue;
594 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000595 // The common cryptos are needed if any of the content does not have DTLS
596 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700597 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000598 common_cryptos_needed = true;
599 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700600 if (first) {
601 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700603 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 return false;
605 }
606 if (common_cryptos.empty()) {
607 // If there's no crypto params, we should just return.
608 return true;
609 }
610 } else {
611 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700612 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 return false;
614 }
615 PruneCryptos(cryptos, &common_cryptos);
616 }
617 }
618
wu@webrtc.org78187522013-10-07 23:32:02 +0000619 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 return false;
621 }
622
623 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700624 for (const std::string& content_name : content_names) {
625 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 continue;
627 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700628 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800630 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 if (!media_desc) {
632 return false;
633 }
634 media_desc->set_cryptos(common_cryptos);
635 }
636 }
637 return true;
638}
639
Steve Anton5c72e712018-12-10 14:25:30 -0800640static std::vector<const ContentInfo*> GetActiveContents(
641 const SessionDescription& description,
642 const MediaSessionOptions& session_options) {
643 std::vector<const ContentInfo*> active_contents;
644 for (size_t i = 0; i < description.contents().size(); ++i) {
645 RTC_DCHECK_LT(i, session_options.media_description_options.size());
646 const ContentInfo& content = description.contents()[i];
647 const MediaDescriptionOptions& media_options =
648 session_options.media_description_options[i];
649 if (!content.rejected && !media_options.stopped &&
650 content.name == media_options.mid) {
651 active_contents.push_back(&content);
652 }
653 }
654 return active_contents;
655}
656
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657template <class C>
658static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800659 for (const auto& codec : codecs) {
660 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 return true;
662 }
663 }
664 return false;
665}
666
667template <class C>
668static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200669 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670}
671
brandtr03d5fb12016-11-22 03:37:59 -0800672template <class C>
673static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
674 for (const auto& codec : codecs) {
675 if (IsFlexfecCodec(codec)) {
676 return true;
677 }
678 }
679 return false;
680}
681
682template <class C>
683static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200684 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800685}
686
zhihuang1c378ed2017-08-17 14:10:50 -0700687// Create a media content to be offered for the given |sender_options|,
688// according to the given options.rtcp_mux, session_options.is_muc, codecs,
689// secure_transport, crypto, and current_streams. If we don't currently have
690// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
691// created (according to crypto_suites). The created content is added to the
692// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693template <class C>
694static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700695 const std::vector<SenderOptions>& sender_options,
696 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000698 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699 const CryptoParamsVec* current_cryptos,
700 const std::vector<std::string>& crypto_suites,
701 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 StreamParamsVec* current_streams,
703 MediaContentDescriptionImpl<C>* offer) {
704 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705
zhihuang1c378ed2017-08-17 14:10:50 -0700706 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700707 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
708 offer->set_rtcp_reduced_size(true);
709 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 offer->set_rtp_header_extensions(rtp_extensions);
711
zhihuang1c378ed2017-08-17 14:10:50 -0700712 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
713 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714 return false;
715 }
716
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 if (secure_policy != SEC_DISABLED) {
718 if (current_cryptos) {
719 AddMediaCryptos(*current_cryptos, offer);
720 }
721 if (offer->cryptos().empty()) {
722 if (!CreateMediaCryptos(crypto_suites, offer)) {
723 return false;
724 }
725 }
726 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727
deadbeef7af91dd2016-12-13 11:29:11 -0800728 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 return false;
730 }
731 return true;
732}
733
734template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000735static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800736 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000737 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800738 const int codec2_id) {
739 const C* codec1 = FindCodecById(codecs1, codec1_id);
740 const C* codec2 = FindCodecById(codecs2, codec2_id);
741 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000742}
743
744template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745static void NegotiateCodecs(const std::vector<C>& local_codecs,
746 const std::vector<C>& offered_codecs,
747 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800748 for (const C& ours : local_codecs) {
749 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700750 // Note that we intentionally only find one matching codec for each of our
751 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800752 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
753 C negotiated = ours;
754 negotiated.IntersectFeedbackParams(theirs);
755 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800756 const auto apt_it =
757 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800758 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800759 RTC_DCHECK(apt_it != theirs.params.end());
760 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 }
Niels Möller039743e2018-10-23 10:07:25 +0200762 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800763 webrtc::H264::GenerateProfileLevelIdForAnswer(
764 ours.params, theirs.params, &negotiated.params);
765 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800766 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700767 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800768 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 }
770 }
deadbeef67cf2c12016-04-13 10:07:16 -0700771 // RFC3264: Although the answerer MAY list the formats in their desired
772 // order of preference, it is RECOMMENDED that unless there is a
773 // specific reason, the answerer list formats in the same relative order
774 // they were present in the offer.
775 std::unordered_map<int, int> payload_type_preferences;
776 int preference = static_cast<int>(offered_codecs.size() + 1);
777 for (const C& codec : offered_codecs) {
778 payload_type_preferences[codec.id] = preference--;
779 }
780 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
781 [&payload_type_preferences](const C& a, const C& b) {
782 return payload_type_preferences[a.id] >
783 payload_type_preferences[b.id];
784 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785}
786
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800787// Finds a codec in |codecs2| that matches |codec_to_match|, which is
788// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
789// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800791static bool FindMatchingCodec(const std::vector<C>& codecs1,
792 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 const C& codec_to_match,
794 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700795 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
796 // codecs' associated codecs correctly. If not, that's a programming error.
797 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
798 [&codec_to_match](const C& codec) {
799 return &codec == &codec_to_match;
800 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800801 for (const C& potential_match : codecs2) {
802 if (potential_match.Matches(codec_to_match)) {
803 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800804 int apt_value_1 = 0;
805 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800806 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
807 &apt_value_1) ||
808 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
809 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100810 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800811 continue;
812 }
813 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
814 apt_value_2)) {
815 continue;
816 }
817 }
818 if (found_codec) {
819 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 }
821 return true;
822 }
823 }
824 return false;
825}
826
zhihuang1c378ed2017-08-17 14:10:50 -0700827// Find the codec in |codec_list| that |rtx_codec| is associated with.
828template <class C>
829static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
830 const C& rtx_codec) {
831 std::string associated_pt_str;
832 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
833 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100834 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
835 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700836 return nullptr;
837 }
838
839 int associated_pt;
840 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100841 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
842 << " of RTX codec " << rtx_codec.name
843 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700844 return nullptr;
845 }
846
847 // Find the associated reference codec for the reference RTX codec.
848 const C* associated_codec = FindCodecById(codec_list, associated_pt);
849 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100850 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
851 << associated_pt << " for RTX codec " << rtx_codec.name
852 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700853 }
854 return associated_codec;
855}
856
857// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858// already exist in |offered_codecs| and ensure the payload types don't
859// collide.
860template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700861static void MergeCodecs(const std::vector<C>& reference_codecs,
862 std::vector<C>* offered_codecs,
863 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800865 for (const C& reference_codec : reference_codecs) {
866 if (!IsRtxCodec(reference_codec) &&
867 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
868 reference_codec, nullptr)) {
869 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 used_pltypes->FindAndSetIdUsed(&codec);
871 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 }
873 }
874
875 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800876 for (const C& reference_codec : reference_codecs) {
877 if (IsRtxCodec(reference_codec) &&
878 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
879 reference_codec, nullptr)) {
880 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700881 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700882 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700883 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700884 continue;
885 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800886 // Find a codec in the offered list that matches the reference codec.
887 // Its payload type may be different than the reference codec.
888 C matching_codec;
889 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800890 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100891 RTC_LOG(LS_WARNING)
892 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800893 continue;
894 }
895
896 rtx_codec.params[kCodecParamAssociatedPayloadType] =
897 rtc::ToString(matching_codec.id);
898 used_pltypes->FindAndSetIdUsed(&rtx_codec);
899 offered_codecs->push_back(rtx_codec);
900 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 }
902}
903
zhihuang1c378ed2017-08-17 14:10:50 -0700904static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
905 const webrtc::RtpExtension& ext_to_match,
906 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700907 auto it =
908 std::find_if(extensions.begin(), extensions.end(),
909 [&ext_to_match](const webrtc::RtpExtension& extension) {
910 // We assume that all URIs are given in a canonical
911 // format.
912 return extension.uri == ext_to_match.uri &&
913 extension.encrypt == ext_to_match.encrypt;
914 });
915 if (it == extensions.end()) {
916 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700917 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700918 if (found_extension) {
919 *found_extension = *it;
920 }
921 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700922}
923
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700925 const webrtc::RtpExtension& ext_to_match,
926 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700927 // We assume that all URIs are given in a canonical format.
928 const webrtc::RtpExtension* found =
929 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
930 ext_to_match.uri);
931 if (!found) {
932 return false;
933 }
934 if (found_extension) {
935 *found_extension = *found;
936 }
937 return true;
938}
939
940static bool FindByUriWithEncryptionPreference(
941 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200942 const webrtc::RtpExtension& ext_to_match,
943 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700944 webrtc::RtpExtension* found_extension) {
945 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700946 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700948 if (extension.uri == ext_to_match.uri) {
949 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700950 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700951 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700952 }
953 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000954 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700955 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956 }
957 }
jbauch5869f502017-06-29 12:31:36 -0700958 if (unencrypted_extension) {
959 if (found_extension) {
960 *found_extension = *unencrypted_extension;
961 }
962 return true;
963 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964 return false;
965}
966
zhihuang1c378ed2017-08-17 14:10:50 -0700967// Adds all extensions from |reference_extensions| to |offered_extensions| that
968// don't already exist in |offered_extensions| and ensure the IDs don't
969// collide. If an extension is added, it's also added to |regular_extensions| or
970// |encrypted_extensions|, and if the extension is in |regular_extensions| or
971// |encrypted_extensions|, its ID is marked as used in |used_ids|.
972// |offered_extensions| is for either audio or video while |regular_extensions|
973// and |encrypted_extensions| are used for both audio and video. There could be
974// overlap between audio extensions and video extensions.
975static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
976 RtpHeaderExtensions* offered_extensions,
977 RtpHeaderExtensions* regular_extensions,
978 RtpHeaderExtensions* encrypted_extensions,
979 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -0700980 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -0700981 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
982 nullptr)) {
olka3c747662017-08-17 06:50:32 -0700983 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -0700984 if (reference_extension.encrypt) {
985 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
986 &existing)) {
987 offered_extensions->push_back(existing);
988 } else {
989 used_ids->FindAndSetIdUsed(&reference_extension);
990 encrypted_extensions->push_back(reference_extension);
991 offered_extensions->push_back(reference_extension);
992 }
olka3c747662017-08-17 06:50:32 -0700993 } else {
zhihuang1c378ed2017-08-17 14:10:50 -0700994 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
995 &existing)) {
996 offered_extensions->push_back(existing);
997 } else {
998 used_ids->FindAndSetIdUsed(&reference_extension);
999 regular_extensions->push_back(reference_extension);
1000 offered_extensions->push_back(reference_extension);
1001 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001002 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 }
1004 }
1005}
1006
jbauch5869f502017-06-29 12:31:36 -07001007static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1008 RtpHeaderExtensions* all_extensions,
1009 UsedRtpHeaderExtensionIds* used_ids) {
1010 RtpHeaderExtensions encrypted_extensions;
1011 for (const webrtc::RtpExtension& extension : *extensions) {
1012 webrtc::RtpExtension existing;
1013 // Don't add encrypted extensions again that were already included in a
1014 // previous offer or regular extensions that are also included as encrypted
1015 // extensions.
1016 if (extension.encrypt ||
1017 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1018 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001019 &existing) &&
1020 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001021 continue;
1022 }
1023
1024 if (FindByUri(*all_extensions, extension, &existing)) {
1025 encrypted_extensions.push_back(existing);
1026 } else {
1027 webrtc::RtpExtension encrypted(extension);
1028 encrypted.encrypt = true;
1029 used_ids->FindAndSetIdUsed(&encrypted);
1030 all_extensions->push_back(encrypted);
1031 encrypted_extensions.push_back(encrypted);
1032 }
1033 }
1034 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001035 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001036}
1037
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038static void NegotiateRtpHeaderExtensions(
1039 const RtpHeaderExtensions& local_extensions,
1040 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001041 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001042 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001043 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001044 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001045 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001046 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001047 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 // We respond with their RTP header extension id.
1049 negotiated_extenstions->push_back(theirs);
1050 }
1051 }
1052}
1053
1054static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001055 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1056 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001057 return absl::EqualsIgnoreCase(
1058 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001059 }),
1060 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001061}
1062
zhihuang1c378ed2017-08-17 14:10:50 -07001063// Create a media content to be answered for the given |sender_options|
1064// according to the given session_options.rtcp_mux, session_options.streams,
1065// codecs, crypto, and current_streams. If we don't currently have crypto (in
1066// current_cryptos) and it is enabled (in secure_policy), crypto is created
1067// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1068// negotiated with the offer. If the negotiation fails, this method returns
1069// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001070template <class C>
1071static bool CreateMediaContentAnswer(
1072 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001073 const MediaDescriptionOptions& media_description_options,
1074 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001076 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077 const CryptoParamsVec* current_cryptos,
1078 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001079 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001080 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081 bool bundle_enabled,
1082 MediaContentDescriptionImpl<C>* answer) {
1083 std::vector<C> negotiated_codecs;
1084 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1085 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001086 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001087
Johannes Kron9581bc42018-10-23 10:17:39 +02001088 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001089 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001090 NegotiateRtpHeaderExtensions(
1091 local_rtp_extenstions, offer->rtp_header_extensions(),
1092 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1094
zhihuang1c378ed2017-08-17 14:10:50 -07001095 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001096 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1097 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1098 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099
1100 if (sdes_policy != SEC_DISABLED) {
1101 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001102 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1103 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104 if (current_cryptos) {
1105 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1106 }
1107 answer->AddCrypto(crypto);
1108 }
1109 }
1110
deadbeef7af91dd2016-12-13 11:29:11 -08001111 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001112 return false;
1113 }
1114
zhihuang1c378ed2017-08-17 14:10:50 -07001115 if (!AddStreamParams(media_description_options.sender_options,
1116 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001117 return false; // Something went seriously wrong.
1118 }
1119
Steve Anton4e70a722017-11-28 14:57:10 -08001120 answer->set_direction(NegotiateRtpTransceiverDirection(
1121 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001122 return true;
1123}
1124
1125static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001126 const std::string& protocol,
1127 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001128 // Since not all applications serialize and deserialize the media protocol,
1129 // we will have to accept |protocol| to be empty.
1130 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 return true;
1132 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001133
zhihuangcf5b37c2016-05-05 11:44:35 -07001134 if (type == MEDIA_TYPE_DATA) {
1135 // Check for SCTP, but also for RTP for RTP-based data channels.
1136 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1137 if (secure_transport) {
1138 // Most likely scenarios first.
1139 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1140 IsPlainRtp(protocol);
1141 } else {
1142 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1143 }
1144 }
1145
1146 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1147 // JSEP specifies.
1148 if (secure_transport) {
1149 // Most likely scenarios first.
1150 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1151 } else {
1152 return IsPlainRtp(protocol);
1153 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001154}
1155
1156static void SetMediaProtocol(bool secure_transport,
1157 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001158 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001159 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001160 else if (secure_transport)
1161 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162 else
1163 desc->set_protocol(kMediaProtocolAvpf);
1164}
1165
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001166// Gets the TransportInfo of the given |content_name| from the
1167// |current_description|. If doesn't exist, returns a new one.
1168static const TransportDescription* GetTransportDescription(
1169 const std::string& content_name,
1170 const SessionDescription* current_description) {
1171 const TransportDescription* desc = NULL;
1172 if (current_description) {
1173 const TransportInfo* info =
1174 current_description->GetTransportInfoByName(content_name);
1175 if (info) {
1176 desc = &info->description;
1177 }
1178 }
1179 return desc;
1180}
1181
1182// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001183static bool IsDtlsActive(const ContentInfo* content,
1184 const SessionDescription* current_description) {
1185 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001186 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001187 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001188
zhihuang1c378ed2017-08-17 14:10:50 -07001189 size_t msection_index = content - &current_description->contents()[0];
1190
1191 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001192 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001193 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001194
zhihuang1c378ed2017-08-17 14:10:50 -07001195 return current_description->transport_infos()[msection_index]
1196 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001197}
1198
Steve Anton8ffb9c32017-08-31 15:45:38 -07001199void MediaDescriptionOptions::AddAudioSender(
1200 const std::string& track_id,
1201 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001202 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001203 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001204}
1205
Steve Anton8ffb9c32017-08-31 15:45:38 -07001206void MediaDescriptionOptions::AddVideoSender(
1207 const std::string& track_id,
1208 const std::vector<std::string>& stream_ids,
1209 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001210 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001211 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001212}
1213
zhihuang1c378ed2017-08-17 14:10:50 -07001214void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1215 const std::string& stream_id) {
1216 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001217 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1218 // than one stream?
1219 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001220}
1221
Steve Anton8ffb9c32017-08-31 15:45:38 -07001222void MediaDescriptionOptions::AddSenderInternal(
1223 const std::string& track_id,
1224 const std::vector<std::string>& stream_ids,
1225 int num_sim_layers) {
1226 // TODO(steveanton): Support any number of stream ids.
1227 RTC_CHECK(stream_ids.size() == 1U);
1228 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229}
1230
zhihuang1c378ed2017-08-17 14:10:50 -07001231bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1232 return std::find_if(media_description_options.begin(),
1233 media_description_options.end(),
1234 [type](const MediaDescriptionOptions& t) {
1235 return t.type == type;
1236 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001237}
1238
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1240 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001241 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242
1243MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1244 ChannelManager* channel_manager,
1245 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001246 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001247 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1248 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001250 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1252 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001253 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001254}
1255
ossudedfd282016-06-14 07:12:39 -07001256const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1257 const {
ossu075af922016-06-14 03:29:38 -07001258 return audio_sendrecv_codecs_;
1259}
1260
1261const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1262 return audio_send_codecs_;
1263}
1264
1265const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1266 return audio_recv_codecs_;
1267}
1268
1269void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001270 const AudioCodecs& send_codecs,
1271 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001272 audio_send_codecs_ = send_codecs;
1273 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001274 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275}
1276
Amit Hilbuch77938e62018-12-21 09:23:38 -08001277static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1278 RTC_DCHECK(extensions);
1279 // Unified Plan also offers the MID and RID header extensions.
1280 extensions->push_back(webrtc::RtpExtension(
1281 webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
1282 extensions->push_back(webrtc::RtpExtension(
1283 webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRidDefaultId));
1284 extensions->push_back(
1285 webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri,
1286 webrtc::RtpExtension::kRepairedRidDefaultId));
1287}
1288
1289RtpHeaderExtensions
1290MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1291 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1292 if (is_unified_plan_) {
1293 AddUnifiedPlanExtensions(&extensions);
1294 }
1295
1296 return extensions;
1297}
1298
1299RtpHeaderExtensions
1300MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1301 RtpHeaderExtensions extensions = video_rtp_extensions_;
1302 if (is_unified_plan_) {
1303 AddUnifiedPlanExtensions(&extensions);
1304 }
1305
1306 return extensions;
1307}
1308
Steve Anton6fe1fba2018-12-11 10:15:23 -08001309std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001310 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001312 // Must have options for each existing section.
1313 if (current_description) {
1314 RTC_DCHECK_LE(current_description->contents().size(),
1315 session_options.media_description_options.size());
1316 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001318 IceCredentialsIterator ice_credentials(
1319 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001320
1321 std::vector<const ContentInfo*> current_active_contents;
1322 if (current_description) {
1323 current_active_contents =
1324 GetActiveContents(*current_description, session_options);
1325 }
1326
1327 StreamParamsVec current_streams =
1328 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329
zhihuang1c378ed2017-08-17 14:10:50 -07001330 AudioCodecs offer_audio_codecs;
1331 VideoCodecs offer_video_codecs;
1332 DataCodecs offer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001333 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001334 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001335
zhihuang1c378ed2017-08-17 14:10:50 -07001336 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001338 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 }
zhihuang1c378ed2017-08-17 14:10:50 -07001340 FilterDataCodecs(&offer_data_codecs,
1341 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001342
1343 RtpHeaderExtensions audio_rtp_extensions;
1344 RtpHeaderExtensions video_rtp_extensions;
Steve Anton8f66ddb2018-12-10 16:08:05 -08001345 GetRtpHdrExtsToOffer(current_active_contents, &audio_rtp_extensions,
1346 &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347
Steve Anton5c72e712018-12-10 14:25:30 -08001348 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001349
zhihuang1c378ed2017-08-17 14:10:50 -07001350 // Iterate through the media description options, matching with existing media
1351 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001352 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001353 for (const MediaDescriptionOptions& media_description_options :
1354 session_options.media_description_options) {
1355 const ContentInfo* current_content = nullptr;
1356 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001357 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001358 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001359 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001360 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001361 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001362 media_description_options.type));
1363 }
1364 switch (media_description_options.type) {
1365 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001366 if (!AddAudioContentForOffer(
1367 media_description_options, session_options, current_content,
1368 current_description, audio_rtp_extensions, offer_audio_codecs,
1369 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001370 return nullptr;
1371 }
1372 break;
1373 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001374 if (!AddVideoContentForOffer(
1375 media_description_options, session_options, current_content,
1376 current_description, video_rtp_extensions, offer_video_codecs,
1377 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001378 return nullptr;
1379 }
1380 break;
1381 case MEDIA_TYPE_DATA:
1382 if (!AddDataContentForOffer(media_description_options, session_options,
1383 current_content, current_description,
1384 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001385 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001386 return nullptr;
1387 }
1388 break;
1389 default:
1390 RTC_NOTREACHED();
1391 }
1392 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001393 }
1394
1395 // Bundle the contents together, if we've been asked to do so, and update any
1396 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001397 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001398 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001399 for (const ContentInfo& content : offer->contents()) {
1400 // TODO(deadbeef): There are conditions that make bundling two media
1401 // descriptions together illegal. For example, they use the same payload
1402 // type to represent different codecs, or same IDs for different header
1403 // extensions. We need to detect this and not try to bundle those media
1404 // descriptions together.
1405 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001406 }
1407 offer->AddGroup(offer_bundle);
1408 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001409 RTC_LOG(LS_ERROR)
1410 << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001411 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001412 }
1413 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001414 RTC_LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001415 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 }
1417 }
Steve Antone831b8c2018-02-01 12:22:16 -08001418
1419 // The following determines how to signal MSIDs to ensure compatibility with
1420 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001421 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001422 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1423 // Plan answerers will look at a=msid and Plan B answerers will look at the
1424 // a=ssrc MSID line.
1425 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1426 cricket::kMsidSignalingSsrcAttribute);
1427 } else {
1428 // Plan B always signals MSID using a=ssrc lines.
1429 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1430 }
1431
Johannes Kron89f874e2018-11-12 10:25:48 +01001432 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1433
Steve Anton6fe1fba2018-12-11 10:15:23 -08001434 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001435}
1436
Steve Anton6fe1fba2018-12-11 10:15:23 -08001437std::unique_ptr<SessionDescription>
1438MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001439 const SessionDescription* offer,
1440 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001441 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001442 if (!offer) {
1443 return nullptr;
1444 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001445
Steve Anton5c72e712018-12-10 14:25:30 -08001446 // Must have options for exactly as many sections as in the offer.
1447 RTC_DCHECK_EQ(offer->contents().size(),
1448 session_options.media_description_options.size());
1449
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001450 IceCredentialsIterator ice_credentials(
1451 session_options.pooled_ice_credentials);
1452
Steve Anton5c72e712018-12-10 14:25:30 -08001453 std::vector<const ContentInfo*> current_active_contents;
1454 if (current_description) {
1455 current_active_contents =
1456 GetActiveContents(*current_description, session_options);
1457 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001458
Steve Anton5c72e712018-12-10 14:25:30 -08001459 StreamParamsVec current_streams =
1460 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001461
zhihuang1c378ed2017-08-17 14:10:50 -07001462 // Get list of all possible codecs that respects existing payload type
1463 // mappings and uses a single payload type space.
1464 //
1465 // Note that these lists may be further filtered for each m= section; this
1466 // step is done just to establish the payload type mappings shared by all
1467 // sections.
1468 AudioCodecs answer_audio_codecs;
1469 VideoCodecs answer_video_codecs;
1470 DataCodecs answer_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001471 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001472 &answer_video_codecs, &answer_data_codecs);
1473
1474 if (!session_options.vad_enabled) {
1475 // If application doesn't want CN codecs in answer.
1476 StripCNCodecs(&answer_audio_codecs);
1477 }
1478 FilterDataCodecs(&answer_data_codecs,
1479 session_options.data_channel_type == DCT_SCTP);
1480
Steve Anton5c72e712018-12-10 14:25:30 -08001481 auto answer = absl::make_unique<SessionDescription>();
1482
1483 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1484 // group in the answer with the appropriate content names.
1485 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1486 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1487 // Transport info shared by the bundle group.
1488 std::unique_ptr<TransportInfo> bundle_transport;
1489
1490 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1491
zhihuang1c378ed2017-08-17 14:10:50 -07001492 // Iterate through the media description options, matching with existing
1493 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001494 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001495 for (const MediaDescriptionOptions& media_description_options :
1496 session_options.media_description_options) {
1497 const ContentInfo* offer_content = &offer->contents()[msection_index];
1498 // Media types and MIDs must match between the remote offer and the
1499 // MediaDescriptionOptions.
1500 RTC_DCHECK(
1501 IsMediaContentOfType(offer_content, media_description_options.type));
1502 RTC_DCHECK(media_description_options.mid == offer_content->name);
1503 const ContentInfo* current_content = nullptr;
1504 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001505 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001506 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001507 }
zhihuang1c378ed2017-08-17 14:10:50 -07001508 switch (media_description_options.type) {
1509 case MEDIA_TYPE_AUDIO:
1510 if (!AddAudioContentForAnswer(
1511 media_description_options, session_options, offer_content,
1512 offer, current_content, current_description,
1513 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001514 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001515 return nullptr;
1516 }
1517 break;
1518 case MEDIA_TYPE_VIDEO:
1519 if (!AddVideoContentForAnswer(
1520 media_description_options, session_options, offer_content,
1521 offer, current_content, current_description,
1522 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001523 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001524 return nullptr;
1525 }
1526 break;
1527 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001528 if (!AddDataContentForAnswer(
1529 media_description_options, session_options, offer_content,
1530 offer, current_content, current_description,
1531 bundle_transport.get(), answer_data_codecs, &current_streams,
1532 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001533 return nullptr;
1534 }
1535 break;
1536 default:
1537 RTC_NOTREACHED();
1538 }
1539 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001540 // See if we can add the newly generated m= section to the BUNDLE group in
1541 // the answer.
1542 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001543 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001544 offer_bundle->HasContentName(added.name)) {
1545 answer_bundle.AddContentName(added.name);
1546 bundle_transport.reset(
1547 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 }
1550
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001551 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1552 // it's empty. RFC5888 says:
1553 //
1554 // A SIP entity that receives an offer that contains an "a=group" line
1555 // with semantics that are understood MUST return an answer that
1556 // contains an "a=group" line with the same semantics.
1557 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001558 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001559 }
deadbeefb7892532017-02-22 19:35:18 -08001560
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001561 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001562 // Share the same ICE credentials and crypto params across all contents,
1563 // as BUNDLE requires.
1564 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001565 RTC_LOG(LS_ERROR)
1566 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001567 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569
deadbeefb7892532017-02-22 19:35:18 -08001570 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001571 RTC_LOG(LS_ERROR)
1572 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001573 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 }
1575 }
1576
Steve Antone831b8c2018-02-01 12:22:16 -08001577 // The following determines how to signal MSIDs to ensure compatibility with
1578 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001579 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001580 // Unified Plan needs to look at what the offer included to find the most
1581 // compatible answer.
1582 if (offer->msid_signaling() == 0) {
1583 // We end up here in one of three cases:
1584 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1585 // matter what we pick here.
1586 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1587 // it also doesn't matter what we pick here.
1588 // 3. Media that's either sendonly or inactive from the remote endpoint.
1589 // We don't have any information to say whether the endpoint is Plan B
1590 // or Unified Plan, so be conservative and send both.
1591 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1592 cricket::kMsidSignalingSsrcAttribute);
1593 } else if (offer->msid_signaling() ==
1594 (cricket::kMsidSignalingMediaSection |
1595 cricket::kMsidSignalingSsrcAttribute)) {
1596 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1597 // probably talking to a Unified Plan endpoint so respond with just
1598 // a=msid.
1599 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1600 } else {
1601 // Otherwise, it's clear which method the offerer is using so repeat that
1602 // back to them.
1603 answer->set_msid_signaling(offer->msid_signaling());
1604 }
1605 } else {
1606 // Plan B always signals MSID using a=ssrc lines.
1607 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1608 }
1609
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611}
1612
ossu075af922016-06-14 03:29:38 -07001613const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1614 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001615 switch (direction) {
1616 // If stream is inactive - generate list as if sendrecv.
1617 case RtpTransceiverDirection::kSendRecv:
1618 case RtpTransceiverDirection::kInactive:
1619 return audio_sendrecv_codecs_;
1620 case RtpTransceiverDirection::kSendOnly:
1621 return audio_send_codecs_;
1622 case RtpTransceiverDirection::kRecvOnly:
1623 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001624 }
Steve Anton1d03a752017-11-27 14:30:09 -08001625 RTC_NOTREACHED();
1626 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001627}
1628
1629const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1630 const RtpTransceiverDirection& offer,
1631 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001632 switch (answer) {
1633 // For inactive and sendrecv answers, generate lists as if we were to accept
1634 // the offer's direction. See RFC 3264 Section 6.1.
1635 case RtpTransceiverDirection::kSendRecv:
1636 case RtpTransceiverDirection::kInactive:
1637 return GetAudioCodecsForOffer(
1638 webrtc::RtpTransceiverDirectionReversed(offer));
1639 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001640 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001641 case RtpTransceiverDirection::kRecvOnly:
1642 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001643 }
Steve Anton1d03a752017-11-27 14:30:09 -08001644 RTC_NOTREACHED();
1645 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001646}
1647
Steve Anton5c72e712018-12-10 14:25:30 -08001648void MergeCodecsFromDescription(
1649 const std::vector<const ContentInfo*>& current_active_contents,
1650 AudioCodecs* audio_codecs,
1651 VideoCodecs* video_codecs,
1652 DataCodecs* data_codecs,
1653 UsedPayloadTypes* used_pltypes) {
1654 for (const ContentInfo* content : current_active_contents) {
1655 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001656 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001657 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001658 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001659 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001660 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001661 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001662 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001663 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001664 const DataContentDescription* data =
Steve Anton5c72e712018-12-10 14:25:30 -08001665 content->media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001666 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1667 }
1668 }
1669}
1670
1671// Getting codecs for an offer involves these steps:
1672//
1673// 1. Construct payload type -> codec mappings for current description.
1674// 2. Add any reference codecs that weren't already present
1675// 3. For each individual media description (m= section), filter codecs based
1676// on the directional attribute (happens in another method).
1677void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001678 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001679 AudioCodecs* audio_codecs,
1680 VideoCodecs* video_codecs,
1681 DataCodecs* data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001682 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001683 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1684 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001685 UsedPayloadTypes used_pltypes;
1686 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1687 video_codecs, data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688
Steve Anton5c72e712018-12-10 14:25:30 -08001689 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001690 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1691 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1692 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1693}
1694
1695// Getting codecs for an answer involves these steps:
1696//
1697// 1. Construct payload type -> codec mappings for current description.
1698// 2. Add any codecs from the offer that weren't already present.
1699// 3. Add any remaining codecs that weren't already present.
1700// 4. For each individual media description (m= section), filter codecs based
1701// on the directional attribute (happens in another method).
1702void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001703 const std::vector<const ContentInfo*>& current_active_contents,
1704 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001705 AudioCodecs* audio_codecs,
1706 VideoCodecs* video_codecs,
1707 DataCodecs* data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001708 // First - get all codecs from the current description if the media type
1709 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1710 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001711 UsedPayloadTypes used_pltypes;
1712 MergeCodecsFromDescription(current_active_contents, audio_codecs,
1713 video_codecs, data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001714
1715 // Second - filter out codecs that we don't support at all and should ignore.
1716 AudioCodecs filtered_offered_audio_codecs;
1717 VideoCodecs filtered_offered_video_codecs;
1718 DataCodecs filtered_offered_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001719 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001720 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1721 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001722 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001723 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1724 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1725 filtered_offered_audio_codecs,
1726 offered_audio_codec, nullptr) &&
1727 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1728 offered_audio_codec, nullptr)) {
1729 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1730 }
1731 }
1732 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1733 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001734 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001735 for (const VideoCodec& offered_video_codec : video->codecs()) {
1736 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1737 filtered_offered_video_codecs,
1738 offered_video_codec, nullptr) &&
1739 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1740 offered_video_codec, nullptr)) {
1741 filtered_offered_video_codecs.push_back(offered_video_codec);
1742 }
1743 }
1744 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1745 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001746 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001747 for (const DataCodec& offered_data_codec : data->codecs()) {
1748 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1749 filtered_offered_data_codecs,
1750 offered_data_codec, nullptr) &&
1751 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1752 offered_data_codec, nullptr)) {
1753 filtered_offered_data_codecs.push_back(offered_data_codec);
1754 }
1755 }
1756 }
1757 }
1758
Steve Anton5c72e712018-12-10 14:25:30 -08001759 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001760 // |remote_offer|.
1761 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1762 &used_pltypes);
1763 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1764 &used_pltypes);
1765 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1766 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767}
1768
1769void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001770 const std::vector<const ContentInfo*>& current_active_contents,
zhihuang1c378ed2017-08-17 14:10:50 -07001771 RtpHeaderExtensions* offer_audio_extensions,
1772 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001773 // All header extensions allocated from the same range to avoid potential
1774 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001776 RtpHeaderExtensions all_regular_extensions;
1777 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778
1779 // First - get all extensions from the current description if the media type
1780 // is used.
1781 // Add them to |used_ids| so the local ids are not reused if a new media
1782 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001783 for (const ContentInfo* content : current_active_contents) {
1784 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1785 const AudioContentDescription* audio =
1786 content->media_description()->as_audio();
1787 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1788 &all_regular_extensions, &all_encrypted_extensions,
1789 &used_ids);
1790 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1791 const VideoContentDescription* video =
1792 content->media_description()->as_video();
1793 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1794 &all_regular_extensions, &all_encrypted_extensions,
1795 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001796 }
1797 }
1798
Steve Anton5c72e712018-12-10 14:25:30 -08001799 // Add our default RTP header extensions that are not in the current
1800 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001801 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1802 &all_regular_extensions, &all_encrypted_extensions,
1803 &used_ids);
1804 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1805 &all_regular_extensions, &all_encrypted_extensions,
1806 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001807
jbauch5869f502017-06-29 12:31:36 -07001808 // TODO(jbauch): Support adding encrypted header extensions to existing
1809 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001810 if (enable_encrypted_rtp_header_extensions_ &&
1811 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001812 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1813 &all_encrypted_extensions, &used_ids);
1814 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1815 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001816 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817}
1818
1819bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001820 const std::string& content_name,
1821 const TransportOptions& transport_options,
1822 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001823 SessionDescription* offer_desc,
1824 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001826 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827 const TransportDescription* current_tdesc =
1828 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001829 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001830 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1831 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001832 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001833 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1834 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001835 }
Steve Anton06817cd2018-12-18 15:55:30 -08001836 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1837 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838}
1839
Steve Anton1a9d3c32018-12-10 17:18:54 -08001840std::unique_ptr<TransportDescription>
1841MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842 const std::string& content_name,
1843 const SessionDescription* offer_desc,
1844 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001845 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001846 bool require_transport_attributes,
1847 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 if (!transport_desc_factory_)
1849 return NULL;
1850 const TransportDescription* offer_tdesc =
1851 GetTransportDescription(content_name, offer_desc);
1852 const TransportDescription* current_tdesc =
1853 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001854 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1855 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001856 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001857}
1858
1859bool MediaSessionDescriptionFactory::AddTransportAnswer(
1860 const std::string& content_name,
1861 const TransportDescription& transport_desc,
1862 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001863 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864 return true;
1865}
1866
zhihuang1c378ed2017-08-17 14:10:50 -07001867// |audio_codecs| = set of all possible codecs that can be used, with correct
1868// payload type mappings
1869//
1870// |supported_audio_codecs| = set of codecs that are supported for the direction
1871// of this m= section
1872//
1873// acd->codecs() = set of previously negotiated codecs for this m= section
1874//
1875// The payload types should come from audio_codecs, but the order should come
1876// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1877// change existing codec priority, and that new codecs are added with the right
1878// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001879bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001880 const MediaDescriptionOptions& media_description_options,
1881 const MediaSessionOptions& session_options,
1882 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001883 const SessionDescription* current_description,
1884 const RtpHeaderExtensions& audio_rtp_extensions,
1885 const AudioCodecs& audio_codecs,
1886 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001887 SessionDescription* desc,
1888 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001889 // Filter audio_codecs (which includes all codecs, with correctly remapped
1890 // payload types) based on transceiver direction.
1891 const AudioCodecs& supported_audio_codecs =
1892 GetAudioCodecsForOffer(media_description_options.direction);
1893
1894 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001895 // Add the codecs from current content if it exists and is not rejected nor
1896 // recycled.
1897 if (current_content && !current_content->rejected &&
1898 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001899 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001900 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001901 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001902 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001903 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1904 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001905 filtered_codecs.push_back(codec);
1906 }
1907 }
1908 }
1909 // Add other supported audio codecs.
1910 AudioCodec found_codec;
1911 for (const AudioCodec& codec : supported_audio_codecs) {
1912 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1913 codec, &found_codec) &&
1914 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1915 codec, nullptr)) {
1916 // Use the |found_codec| from |audio_codecs| because it has the correctly
1917 // mapped payload type.
1918 filtered_codecs.push_back(found_codec);
1919 }
1920 }
deadbeef44f08192015-12-15 16:20:09 -08001921
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001922 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001923 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1924 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001925
kwiberg31022942016-03-11 14:18:21 -08001926 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001927 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001928 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1929 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001930 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001931 media_description_options.sender_options, session_options,
1932 filtered_codecs, sdes_policy, GetCryptos(current_content),
1933 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001934 return false;
1935 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001936
1937 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1938 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001939
Steve Anton4e70a722017-11-28 14:57:10 -08001940 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001941
Steve Anton5adfafd2017-12-20 16:34:00 -08001942 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001943 media_description_options.stopped, audio.release());
1944 if (!AddTransportOffer(media_description_options.mid,
1945 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001946 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001947 return false;
1948 }
1949
1950 return true;
1951}
1952
1953bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001954 const MediaDescriptionOptions& media_description_options,
1955 const MediaSessionOptions& session_options,
1956 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001957 const SessionDescription* current_description,
1958 const RtpHeaderExtensions& video_rtp_extensions,
1959 const VideoCodecs& video_codecs,
1960 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001961 SessionDescription* desc,
1962 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001963 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001964 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1965 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001966
kwiberg31022942016-03-11 14:18:21 -08001967 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001968 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001969 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1970 &crypto_suites);
1971
1972 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001973 // Add the codecs from current content if it exists and is not rejected nor
1974 // recycled.
1975 if (current_content && !current_content->rejected &&
1976 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001977 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07001978 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001979 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001980 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001981 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07001982 nullptr)) {
1983 filtered_codecs.push_back(codec);
1984 }
1985 }
1986 }
1987 // Add other supported video codecs.
1988 VideoCodec found_codec;
1989 for (const VideoCodec& codec : video_codecs_) {
1990 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1991 &found_codec) &&
1992 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1993 nullptr)) {
1994 // Use the |found_codec| from |video_codecs| because it has the correctly
1995 // mapped payload type.
1996 filtered_codecs.push_back(found_codec);
1997 }
1998 }
1999
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002000 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002001 media_description_options.sender_options, session_options,
2002 filtered_codecs, sdes_policy, GetCryptos(current_content),
2003 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002004 return false;
2005 }
2006
zhihuang1c378ed2017-08-17 14:10:50 -07002007 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002008
2009 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2010 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002011
Steve Anton4e70a722017-11-28 14:57:10 -08002012 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002013
Steve Anton5adfafd2017-12-20 16:34:00 -08002014 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002015 media_description_options.stopped, video.release());
2016 if (!AddTransportOffer(media_description_options.mid,
2017 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002018 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002019 return false;
2020 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002021 return true;
2022}
2023
2024bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002025 const MediaDescriptionOptions& media_description_options,
2026 const MediaSessionOptions& session_options,
2027 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002028 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07002029 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002030 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002031 SessionDescription* desc,
2032 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002033 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2034
kwiberg31022942016-03-11 14:18:21 -08002035 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07002036 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2037 // If the DataChannel type is not specified, use the DataChannel type in
2038 // the current description.
2039 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002040 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002041 is_sctp = (current_content->media_description()->protocol() ==
2042 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002043 }
deadbeef44f08192015-12-15 16:20:09 -08002044
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002045 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002046 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2047 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002048 std::vector<std::string> crypto_suites;
2049 if (is_sctp) {
2050 // SDES doesn't make sense for SCTP, so we disable it, and we only
2051 // get SDES crypto suites for RTP-based data channels.
2052 sdes_policy = cricket::SEC_DISABLED;
2053 // Unlike SetMediaProtocol below, we need to set the protocol
2054 // before we call CreateMediaContentOffer. Otherwise,
2055 // CreateMediaContentOffer won't know this is SCTP and will
2056 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002057 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2058 // it's safe to do so. Older versions of webrtc would reject these
2059 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002060 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2061 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002062 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002063 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002064 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002065 }
2066
zhihuang1c378ed2017-08-17 14:10:50 -07002067 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002068 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002069 media_description_options.sender_options, session_options,
2070 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2071 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002072 return false;
2073 }
2074
2075 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002076 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002077 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002078 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002079 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002080 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002081 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002082 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002083 }
zhihuang1c378ed2017-08-17 14:10:50 -07002084 if (!AddTransportOffer(media_description_options.mid,
2085 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002086 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002087 return false;
2088 }
2089 return true;
2090}
2091
zhihuang1c378ed2017-08-17 14:10:50 -07002092// |audio_codecs| = set of all possible codecs that can be used, with correct
2093// payload type mappings
2094//
2095// |supported_audio_codecs| = set of codecs that are supported for the direction
2096// of this m= section
2097//
2098// acd->codecs() = set of previously negotiated codecs for this m= section
2099//
2100// The payload types should come from audio_codecs, but the order should come
2101// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2102// change existing codec priority, and that new codecs are added with the right
2103// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002104bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002105 const MediaDescriptionOptions& media_description_options,
2106 const MediaSessionOptions& session_options,
2107 const ContentInfo* offer_content,
2108 const SessionDescription* offer_description,
2109 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002110 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002111 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002112 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002113 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002114 SessionDescription* answer,
2115 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002116 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002117 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002118 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002119
Steve Anton1a9d3c32018-12-10 17:18:54 -08002120 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002121 media_description_options.mid, offer_description,
2122 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002123 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002124 if (!audio_transport) {
2125 return false;
2126 }
2127
zhihuang1c378ed2017-08-17 14:10:50 -07002128 // Pick codecs based on the requested communications direction in the offer
2129 // and the selected direction in the answer.
2130 // Note these will be filtered one final time in CreateMediaContentAnswer.
2131 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002132 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002133 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002134 AudioCodecs supported_audio_codecs =
2135 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2136
2137 AudioCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002138 // Add the codecs from current content if it exists and is not rejected nor
2139 // recycled.
2140 if (current_content && !current_content->rejected &&
2141 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002142 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002143 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002144 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002145 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002146 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2147 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002148 filtered_codecs.push_back(codec);
2149 }
2150 }
2151 }
2152 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002153 for (const AudioCodec& codec : supported_audio_codecs) {
2154 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002155 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002156 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2157 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002158 // We should use the local codec with local parameters and the codec id
2159 // would be correctly mapped in |NegotiateCodecs|.
2160 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002161 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002162 }
2163
zhihuang1c378ed2017-08-17 14:10:50 -07002164 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2165 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002166 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002167 new AudioContentDescription());
2168 // Do not require or create SDES cryptos if DTLS is used.
2169 cricket::SecurePolicy sdes_policy =
2170 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2171 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002172 offer_audio_description, media_description_options, session_options,
2173 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton8f66ddb2018-12-10 16:08:05 -08002174 audio_rtp_header_extensions(),
Steve Anton1b8773d2018-04-06 11:13:34 -07002175 enable_encrypted_rtp_header_extensions_, current_streams,
2176 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002177 return false; // Fails the session setup.
2178 }
2179
deadbeefb7892532017-02-22 19:35:18 -08002180 bool secure = bundle_transport ? bundle_transport->description.secure()
2181 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002182 bool rejected = media_description_options.stopped ||
2183 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002184 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2185 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002186 if (!AddTransportAnswer(media_description_options.mid,
2187 *(audio_transport.get()), answer)) {
2188 return false;
2189 }
2190
2191 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002192 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2193 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002194 }
2195
zhihuang1c378ed2017-08-17 14:10:50 -07002196 answer->AddContent(media_description_options.mid, offer_content->type,
2197 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002198 return true;
2199}
2200
2201bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002202 const MediaDescriptionOptions& media_description_options,
2203 const MediaSessionOptions& session_options,
2204 const ContentInfo* offer_content,
2205 const SessionDescription* offer_description,
2206 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002207 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002208 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002209 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002210 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002211 SessionDescription* answer,
2212 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002213 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002214 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002215 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002216
Steve Anton1a9d3c32018-12-10 17:18:54 -08002217 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002218 media_description_options.mid, offer_description,
2219 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002220 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002221 if (!video_transport) {
2222 return false;
2223 }
2224
zhihuang1c378ed2017-08-17 14:10:50 -07002225 VideoCodecs filtered_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08002226 // Add the codecs from current content if it exists and is not rejected nor
2227 // recycled.
2228 if (current_content && !current_content->rejected &&
2229 current_content->name == media_description_options.mid) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002230 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002231 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002232 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002233 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002234 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002235 nullptr)) {
2236 filtered_codecs.push_back(codec);
2237 }
2238 }
2239 }
2240 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002241 for (const VideoCodec& codec : video_codecs_) {
2242 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002243 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002244 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2245 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002246 // We should use the local codec with local parameters and the codec id
2247 // would be correctly mapped in |NegotiateCodecs|.
2248 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002249 }
2250 }
2251
2252 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2253 session_options.bundle_enabled;
2254
kwiberg31022942016-03-11 14:18:21 -08002255 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002256 new VideoContentDescription());
2257 // Do not require or create SDES cryptos if DTLS is used.
2258 cricket::SecurePolicy sdes_policy =
2259 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002260 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002261 offer_video_description, media_description_options, session_options,
2262 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton8f66ddb2018-12-10 16:08:05 -08002263 video_rtp_header_extensions(),
Steve Anton1b8773d2018-04-06 11:13:34 -07002264 enable_encrypted_rtp_header_extensions_, current_streams,
2265 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002266 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002267 }
deadbeefb7892532017-02-22 19:35:18 -08002268 bool secure = bundle_transport ? bundle_transport->description.secure()
2269 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002270 bool rejected = media_description_options.stopped ||
2271 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002272 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2273 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002274 if (!AddTransportAnswer(media_description_options.mid,
2275 *(video_transport.get()), answer)) {
2276 return false;
2277 }
2278
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002279 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002280 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002281 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002282 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2283 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002284 }
zhihuang1c378ed2017-08-17 14:10:50 -07002285 answer->AddContent(media_description_options.mid, offer_content->type,
2286 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002287 return true;
2288}
2289
2290bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002291 const MediaDescriptionOptions& media_description_options,
2292 const MediaSessionOptions& session_options,
2293 const ContentInfo* offer_content,
2294 const SessionDescription* offer_description,
2295 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002296 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002297 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002298 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002299 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002300 SessionDescription* answer,
2301 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002302 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002303 media_description_options.mid, offer_description,
2304 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002305 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306 if (!data_transport) {
2307 return false;
2308 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002309
kwiberg31022942016-03-11 14:18:21 -08002310 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002311 new DataContentDescription());
2312 // Do not require or create SDES cryptos if DTLS is used.
2313 cricket::SecurePolicy sdes_policy =
2314 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002315 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2316 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002317 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2318 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002319 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002320 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002321 offer_data_description, media_description_options, session_options,
2322 data_codecs, sdes_policy, GetCryptos(current_content),
2323 RtpHeaderExtensions(), enable_encrypted_rtp_header_extensions_,
2324 current_streams, bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002325 return false; // Fails the session setup.
2326 }
2327
zstein4b2e0822017-02-17 19:48:38 -08002328 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002329 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2330 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2331
deadbeefb7892532017-02-22 19:35:18 -08002332 bool secure = bundle_transport ? bundle_transport->description.secure()
2333 : data_transport->secure();
2334
zhihuang1c378ed2017-08-17 14:10:50 -07002335 bool rejected = session_options.data_channel_type == DCT_NONE ||
2336 media_description_options.stopped ||
2337 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002338 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2339 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002340 if (!AddTransportAnswer(media_description_options.mid,
2341 *(data_transport.get()), answer)) {
2342 return false;
2343 }
2344
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002345 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002346 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002347 } else {
2348 // RFC 3264
2349 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002350 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002351 }
zhihuang1c378ed2017-08-17 14:10:50 -07002352 answer->AddContent(media_description_options.mid, offer_content->type,
2353 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002354 return true;
2355}
2356
zhihuang1c378ed2017-08-17 14:10:50 -07002357void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2358 audio_sendrecv_codecs_.clear();
2359 all_audio_codecs_.clear();
2360 // Compute the audio codecs union.
2361 for (const AudioCodec& send : audio_send_codecs_) {
2362 all_audio_codecs_.push_back(send);
2363 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2364 send, nullptr)) {
2365 // It doesn't make sense to have an RTX codec we support sending but not
2366 // receiving.
2367 RTC_DCHECK(!IsRtxCodec(send));
2368 }
2369 }
2370 for (const AudioCodec& recv : audio_recv_codecs_) {
2371 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2372 recv, nullptr)) {
2373 all_audio_codecs_.push_back(recv);
2374 }
2375 }
2376 // Use NegotiateCodecs to merge our codec lists, since the operation is
2377 // essentially the same. Put send_codecs as the offered_codecs, which is the
2378 // order we'd like to follow. The reasoning is that encoding is usually more
2379 // expensive than decoding, and prioritizing a codec in the send list probably
2380 // means it's a codec we can handle efficiently.
2381 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2382 &audio_sendrecv_codecs_);
2383}
2384
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002385bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002386 return (content && (content->type == MediaProtocolType::kRtp ||
2387 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002388}
2389
2390bool IsAudioContent(const ContentInfo* content) {
2391 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2392}
2393
2394bool IsVideoContent(const ContentInfo* content) {
2395 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2396}
2397
2398bool IsDataContent(const ContentInfo* content) {
2399 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2400}
2401
deadbeef0ed85b22016-02-23 17:24:52 -08002402const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2403 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002404 for (const ContentInfo& content : contents) {
2405 if (IsMediaContentOfType(&content, media_type)) {
2406 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407 }
2408 }
deadbeef0ed85b22016-02-23 17:24:52 -08002409 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410}
2411
2412const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2413 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2414}
2415
2416const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2417 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2418}
2419
2420const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2421 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2422}
2423
Steve Antonad7bffc2018-01-22 10:21:56 -08002424const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2425 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002426 if (sdesc == nullptr) {
2427 return nullptr;
2428 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002429
2430 return GetFirstMediaContent(sdesc->contents(), media_type);
2431}
2432
2433const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2434 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2435}
2436
2437const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2438 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2439}
2440
2441const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2442 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2443}
2444
2445const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002446 const SessionDescription* sdesc,
2447 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002449 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450}
2451
2452const AudioContentDescription* GetFirstAudioContentDescription(
2453 const SessionDescription* sdesc) {
2454 return static_cast<const AudioContentDescription*>(
2455 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2456}
2457
2458const VideoContentDescription* GetFirstVideoContentDescription(
2459 const SessionDescription* sdesc) {
2460 return static_cast<const VideoContentDescription*>(
2461 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2462}
2463
2464const DataContentDescription* GetFirstDataContentDescription(
2465 const SessionDescription* sdesc) {
2466 return static_cast<const DataContentDescription*>(
2467 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2468}
2469
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002470//
2471// Non-const versions of the above functions.
2472//
2473
Steve Anton36b29d12017-10-30 09:57:42 -07002474ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002475 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002476 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002477 if (IsMediaContentOfType(&content, media_type)) {
2478 return &content;
2479 }
2480 }
2481 return nullptr;
2482}
2483
Steve Anton36b29d12017-10-30 09:57:42 -07002484ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002485 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2486}
2487
Steve Anton36b29d12017-10-30 09:57:42 -07002488ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002489 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2490}
2491
Steve Anton36b29d12017-10-30 09:57:42 -07002492ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002493 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2494}
2495
Steve Antonad7bffc2018-01-22 10:21:56 -08002496ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2497 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002498 if (sdesc == nullptr) {
2499 return nullptr;
2500 }
2501
Steve Anton36b29d12017-10-30 09:57:42 -07002502 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002503}
2504
2505ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2506 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2507}
2508
2509ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2510 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2511}
2512
2513ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2514 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2515}
2516
2517MediaContentDescription* GetFirstMediaContentDescription(
2518 SessionDescription* sdesc,
2519 MediaType media_type) {
2520 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002521 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002522}
2523
2524AudioContentDescription* GetFirstAudioContentDescription(
2525 SessionDescription* sdesc) {
2526 return static_cast<AudioContentDescription*>(
2527 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2528}
2529
2530VideoContentDescription* GetFirstVideoContentDescription(
2531 SessionDescription* sdesc) {
2532 return static_cast<VideoContentDescription*>(
2533 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2534}
2535
2536DataContentDescription* GetFirstDataContentDescription(
2537 SessionDescription* sdesc) {
2538 return static_cast<DataContentDescription*>(
2539 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2540}
2541
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002542} // namespace cricket