blob: 889576c306d67b3fcc5ed8cf1e4f89494cd854d9 [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
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020021#include "absl/types/optional.h"
Patrik Höglund7aee3d52017-11-15 13:15:17 +010022#include "api/cryptoparams.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020023#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "media/base/h264_profile_level_id.h"
25#include "media/base/mediaconstants.h"
26#include "p2p/base/p2pconstants.h"
27#include "pc/channelmanager.h"
Steve Anton1d03a752017-11-27 14:30:09 -080028#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "pc/srtpfilter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/checks.h"
31#include "rtc_base/helpers.h"
32#include "rtc_base/logging.h"
33#include "rtc_base/stringutils.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.
292static void GetCurrentStreamParams(const SessionDescription* sdesc,
293 StreamParamsVec* stream_params) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800294 RTC_DCHECK(stream_params);
295 if (!sdesc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 return;
Steve Antonb1c1de12017-12-21 15:14:30 -0800297 }
298 for (const ContentInfo& content : sdesc->contents()) {
299 if (!content.media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 continue;
301 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800302 for (const StreamParams& params : content.media_description()->streams()) {
303 stream_params->push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304 }
305 }
306}
307
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000308// Filters the data codecs for the data channel type.
309void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
310 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700311 const char* codec_name =
312 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700313 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
314 [&codec_name](const DataCodec& codec) {
315 return CodecNamesEq(codec.name, codec_name);
316 }),
317 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000318}
319
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320template <typename IdStruct>
321class UsedIds {
322 public:
323 UsedIds(int min_allowed_id, int max_allowed_id)
324 : min_allowed_id_(min_allowed_id),
325 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200326 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000327
328 // Loops through all Id in |ids| and changes its id if it is
329 // already in use by another IdStruct. Call this methods with all Id
330 // in a session description to make sure no duplicate ids exists.
331 // Note that typename Id must be a type of IdStruct.
332 template <typename Id>
333 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700334 for (const Id& id : *ids) {
335 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336 }
337 }
338
339 // Finds and sets an unused id if the |idstruct| id is already in use.
340 void FindAndSetIdUsed(IdStruct* idstruct) {
341 const int original_id = idstruct->id;
342 int new_id = idstruct->id;
343
344 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
345 // If the original id is not in range - this is an id that can't be
346 // dynamically changed.
347 return;
348 }
349
350 if (IsIdUsed(original_id)) {
351 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100352 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
353 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354 idstruct->id = new_id;
355 }
356 SetIdUsed(new_id);
357 }
358
359 private:
360 // Returns the first unused id in reverse order.
361 // This hopefully reduce the risk of more collisions. We want to change the
362 // default ids as little as possible.
363 int FindUnusedId() {
364 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
365 --next_id_;
366 }
nisseede5da42017-01-12 05:15:36 -0800367 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368 return next_id_;
369 }
370
Yves Gerey665174f2018-06-19 15:03:05 +0200371 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372
Yves Gerey665174f2018-06-19 15:03:05 +0200373 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374
375 const int min_allowed_id_;
376 const int max_allowed_id_;
377 int next_id_;
378 std::set<int> id_set_;
379};
380
381// Helper class used for finding duplicate RTP payload types among audio, video
382// and data codecs. When bundle is used the payload types may not collide.
383class UsedPayloadTypes : public UsedIds<Codec> {
384 public:
385 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200386 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387
388 private:
389 static const int kDynamicPayloadTypeMin = 96;
390 static const int kDynamicPayloadTypeMax = 127;
391};
392
393// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200394// audio and video extensions. Only applies to one-byte header extensions at the
395// moment. ids > 14 will always be reported as available.
396// TODO(kron): This class needs to be refactored when we start to send two-byte
397// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700398class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000399 public:
400 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200401 : UsedIds<webrtc::RtpExtension>(
402 webrtc::RtpExtension::kMinId,
403 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404
405 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406};
407
zhihuang1c378ed2017-08-17 14:10:50 -0700408// Adds a StreamParams for each SenderOptions in |sender_options| to
409// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410// |current_params| - All currently known StreamParams of any media type.
411template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700412static bool AddStreamParams(
413 const std::vector<SenderOptions>& sender_options,
414 const std::string& rtcp_cname,
415 StreamParamsVec* current_streams,
416 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700417 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700418 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700419 return true;
420 }
421
Noah Richards2e7a0982015-05-18 14:02:54 -0700422 const bool include_rtx_streams =
423 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424
brandtr03d5fb12016-11-22 03:37:59 -0800425 const bool include_flexfec_stream =
426 ContainsFlexfecCodec(content_description->codecs());
427
zhihuang1c378ed2017-08-17 14:10:50 -0700428 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 // groupid is empty for StreamParams generated using
430 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700431 StreamParams* param =
432 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000433 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700434 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200435 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700436 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700438 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000439 // Add the generated ssrc.
440 for (size_t i = 0; i < ssrcs.size(); ++i) {
441 stream_param.ssrcs.push_back(ssrcs[i]);
442 }
zhihuang1c378ed2017-08-17 14:10:50 -0700443 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000444 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
445 stream_param.ssrc_groups.push_back(group);
446 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700447 // Generate extra ssrcs for include_rtx_streams case.
448 if (include_rtx_streams) {
449 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200450 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700451 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
452 &rtx_ssrcs);
453 for (size_t i = 0; i < ssrcs.size(); ++i) {
454 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
455 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 }
brandtr03d5fb12016-11-22 03:37:59 -0800457 // Generate extra ssrc for include_flexfec_stream case.
458 if (include_flexfec_stream) {
459 // TODO(brandtr): Update when we support multistream protection.
460 if (ssrcs.size() == 1) {
461 std::vector<uint32_t> flexfec_ssrcs;
462 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
463 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
brandtr03d5fb12016-11-22 03:37:59 -0800464 } else if (!ssrcs.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100465 RTC_LOG(LS_WARNING)
brandtr03d5fb12016-11-22 03:37:59 -0800466 << "Our FlexFEC implementation only supports protecting "
Jonas Olsson45cc8902018-02-13 10:37:07 +0100467 "a single media streams. This session has multiple "
468 "media streams however, so no FlexFEC SSRC will be generated.";
brandtr03d5fb12016-11-22 03:37:59 -0800469 }
470 }
zhihuang1c378ed2017-08-17 14:10:50 -0700471 stream_param.cname = rtcp_cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800472 stream_param.set_stream_ids(sender.stream_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 content_description->AddStream(stream_param);
474
475 // Store the new StreamParams in current_streams.
476 // This is necessary so that we can use the CNAME for other media types.
477 current_streams->push_back(stream_param);
478 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700479 // Use existing generated SSRCs/groups, but update the sync_label if
480 // necessary. This may be needed if a MediaStreamTrack was moved from one
481 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800482 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000483 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 }
485 }
486 return true;
487}
488
489// Updates the transport infos of the |sdesc| according to the given
490// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800491// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
492// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
494 SessionDescription* sdesc) {
495 // The bundle should not be empty.
496 if (!sdesc || !bundle_group.FirstContentName()) {
497 return false;
498 }
499
500 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700501 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 const TransportInfo* selected_transport_info =
503 sdesc->GetTransportInfoByName(selected_content_name);
504 if (!selected_transport_info) {
505 return false;
506 }
507
508 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700509 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700511 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800513 ConnectionRole selected_connection_role =
514 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700515 for (TransportInfo& transport_info : sdesc->transport_infos()) {
516 if (bundle_group.HasContentName(transport_info.content_name) &&
517 transport_info.content_name != selected_content_name) {
518 transport_info.description.ice_ufrag = selected_ufrag;
519 transport_info.description.ice_pwd = selected_pwd;
520 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 }
522 }
523 return true;
524}
525
526// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
527// sets it to |cryptos|.
528static bool GetCryptosByName(const SessionDescription* sdesc,
529 const std::string& content_name,
530 CryptoParamsVec* cryptos) {
531 if (!sdesc || !cryptos) {
532 return false;
533 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800535 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 return false;
537 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800538 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 return true;
540}
541
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
543// which are not available in |filter|.
544static void PruneCryptos(const CryptoParamsVec& filter,
545 CryptoParamsVec* target_cryptos) {
546 if (!target_cryptos) {
547 return;
548 }
tzik21995802018-04-26 17:38:28 +0900549
550 target_cryptos->erase(
551 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
552 // Returns true if the |crypto|'s cipher_suite is not
553 // found in |filter|.
554 [&filter](const CryptoParams& crypto) {
555 for (const CryptoParams& entry : filter) {
556 if (entry.cipher_suite == crypto.cipher_suite)
557 return false;
558 }
559 return true;
560 }),
561 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562}
563
Steve Antonfa2260d2017-12-28 16:38:23 -0800564bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800565 return protocol.empty() ||
566 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
567}
568
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569static bool IsRtpContent(SessionDescription* sdesc,
570 const std::string& content_name) {
571 bool is_rtp = false;
572 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800573 if (content && content->media_description()) {
574 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 }
576 return is_rtp;
577}
578
579// Updates the crypto parameters of the |sdesc| according to the given
580// |bundle_group|. The crypto parameters of all the contents within the
581// |bundle_group| should be updated to use the common subset of the
582// available cryptos.
583static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
584 SessionDescription* sdesc) {
585 // The bundle should not be empty.
586 if (!sdesc || !bundle_group.FirstContentName()) {
587 return false;
588 }
589
wu@webrtc.org78187522013-10-07 23:32:02 +0000590 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 // Get the common cryptos.
592 const ContentNames& content_names = bundle_group.content_names();
593 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700594 bool first = true;
595 for (const std::string& content_name : content_names) {
596 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 continue;
598 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000599 // The common cryptos are needed if any of the content does not have DTLS
600 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700601 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000602 common_cryptos_needed = true;
603 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700604 if (first) {
605 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700607 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 return false;
609 }
610 if (common_cryptos.empty()) {
611 // If there's no crypto params, we should just return.
612 return true;
613 }
614 } else {
615 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700616 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 return false;
618 }
619 PruneCryptos(cryptos, &common_cryptos);
620 }
621 }
622
wu@webrtc.org78187522013-10-07 23:32:02 +0000623 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 return false;
625 }
626
627 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700628 for (const std::string& content_name : content_names) {
629 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 continue;
631 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700632 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000633 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800634 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000635 if (!media_desc) {
636 return false;
637 }
638 media_desc->set_cryptos(common_cryptos);
639 }
640 }
641 return true;
642}
643
644template <class C>
645static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800646 for (const auto& codec : codecs) {
647 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 return true;
649 }
650 }
651 return false;
652}
653
654template <class C>
655static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800656 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657}
658
brandtr03d5fb12016-11-22 03:37:59 -0800659template <class C>
660static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
661 for (const auto& codec : codecs) {
662 if (IsFlexfecCodec(codec)) {
663 return true;
664 }
665 }
666 return false;
667}
668
669template <class C>
670static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800671 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800672}
673
zhihuang1c378ed2017-08-17 14:10:50 -0700674// Create a media content to be offered for the given |sender_options|,
675// according to the given options.rtcp_mux, session_options.is_muc, codecs,
676// secure_transport, crypto, and current_streams. If we don't currently have
677// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
678// created (according to crypto_suites). The created content is added to the
679// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680template <class C>
681static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700682 const std::vector<SenderOptions>& sender_options,
683 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000685 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 const CryptoParamsVec* current_cryptos,
687 const std::vector<std::string>& crypto_suites,
688 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 StreamParamsVec* current_streams,
690 MediaContentDescriptionImpl<C>* offer) {
691 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692
zhihuang1c378ed2017-08-17 14:10:50 -0700693 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700694 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
695 offer->set_rtcp_reduced_size(true);
696 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697 offer->set_rtp_header_extensions(rtp_extensions);
698
zhihuang1c378ed2017-08-17 14:10:50 -0700699 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
700 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 return false;
702 }
703
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 if (secure_policy != SEC_DISABLED) {
705 if (current_cryptos) {
706 AddMediaCryptos(*current_cryptos, offer);
707 }
708 if (offer->cryptos().empty()) {
709 if (!CreateMediaCryptos(crypto_suites, offer)) {
710 return false;
711 }
712 }
713 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714
deadbeef7af91dd2016-12-13 11:29:11 -0800715 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716 return false;
717 }
718 return true;
719}
720
721template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000722static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800723 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000724 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800725 const int codec2_id) {
726 const C* codec1 = FindCodecById(codecs1, codec1_id);
727 const C* codec2 = FindCodecById(codecs2, codec2_id);
728 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000729}
730
731template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732static void NegotiateCodecs(const std::vector<C>& local_codecs,
733 const std::vector<C>& offered_codecs,
734 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800735 for (const C& ours : local_codecs) {
736 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700737 // Note that we intentionally only find one matching codec for each of our
738 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800739 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
740 C negotiated = ours;
741 negotiated.IntersectFeedbackParams(theirs);
742 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800743 const auto apt_it =
744 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800745 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800746 RTC_DCHECK(apt_it != theirs.params.end());
747 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 }
magjedf823ede2016-11-12 09:53:04 -0800749 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
750 webrtc::H264::GenerateProfileLevelIdForAnswer(
751 ours.params, theirs.params, &negotiated.params);
752 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800753 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700754 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800755 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756 }
757 }
deadbeef67cf2c12016-04-13 10:07:16 -0700758 // RFC3264: Although the answerer MAY list the formats in their desired
759 // order of preference, it is RECOMMENDED that unless there is a
760 // specific reason, the answerer list formats in the same relative order
761 // they were present in the offer.
762 std::unordered_map<int, int> payload_type_preferences;
763 int preference = static_cast<int>(offered_codecs.size() + 1);
764 for (const C& codec : offered_codecs) {
765 payload_type_preferences[codec.id] = preference--;
766 }
767 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
768 [&payload_type_preferences](const C& a, const C& b) {
769 return payload_type_preferences[a.id] >
770 payload_type_preferences[b.id];
771 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772}
773
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800774// Finds a codec in |codecs2| that matches |codec_to_match|, which is
775// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
776// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800778static bool FindMatchingCodec(const std::vector<C>& codecs1,
779 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780 const C& codec_to_match,
781 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700782 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
783 // codecs' associated codecs correctly. If not, that's a programming error.
784 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
785 [&codec_to_match](const C& codec) {
786 return &codec == &codec_to_match;
787 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800788 for (const C& potential_match : codecs2) {
789 if (potential_match.Matches(codec_to_match)) {
790 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800791 int apt_value_1 = 0;
792 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800793 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
794 &apt_value_1) ||
795 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
796 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100797 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800798 continue;
799 }
800 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
801 apt_value_2)) {
802 continue;
803 }
804 }
805 if (found_codec) {
806 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 }
808 return true;
809 }
810 }
811 return false;
812}
813
zhihuang1c378ed2017-08-17 14:10:50 -0700814// Find the codec in |codec_list| that |rtx_codec| is associated with.
815template <class C>
816static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
817 const C& rtx_codec) {
818 std::string associated_pt_str;
819 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
820 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100821 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
822 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700823 return nullptr;
824 }
825
826 int associated_pt;
827 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100828 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
829 << " of RTX codec " << rtx_codec.name
830 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700831 return nullptr;
832 }
833
834 // Find the associated reference codec for the reference RTX codec.
835 const C* associated_codec = FindCodecById(codec_list, associated_pt);
836 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100837 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
838 << associated_pt << " for RTX codec " << rtx_codec.name
839 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700840 }
841 return associated_codec;
842}
843
844// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845// already exist in |offered_codecs| and ensure the payload types don't
846// collide.
847template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700848static void MergeCodecs(const std::vector<C>& reference_codecs,
849 std::vector<C>* offered_codecs,
850 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852 for (const C& reference_codec : reference_codecs) {
853 if (!IsRtxCodec(reference_codec) &&
854 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
855 reference_codec, nullptr)) {
856 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 used_pltypes->FindAndSetIdUsed(&codec);
858 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 }
860 }
861
862 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800863 for (const C& reference_codec : reference_codecs) {
864 if (IsRtxCodec(reference_codec) &&
865 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
866 reference_codec, nullptr)) {
867 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700868 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700869 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700870 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700871 continue;
872 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800873 // Find a codec in the offered list that matches the reference codec.
874 // Its payload type may be different than the reference codec.
875 C matching_codec;
876 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800877 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100878 RTC_LOG(LS_WARNING)
879 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800880 continue;
881 }
882
883 rtx_codec.params[kCodecParamAssociatedPayloadType] =
884 rtc::ToString(matching_codec.id);
885 used_pltypes->FindAndSetIdUsed(&rtx_codec);
886 offered_codecs->push_back(rtx_codec);
887 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888 }
889}
890
zhihuang1c378ed2017-08-17 14:10:50 -0700891static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
892 const webrtc::RtpExtension& ext_to_match,
893 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700894 auto it =
895 std::find_if(extensions.begin(), extensions.end(),
896 [&ext_to_match](const webrtc::RtpExtension& extension) {
897 // We assume that all URIs are given in a canonical
898 // format.
899 return extension.uri == ext_to_match.uri &&
900 extension.encrypt == ext_to_match.encrypt;
901 });
902 if (it == extensions.end()) {
903 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700904 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700905 if (found_extension) {
906 *found_extension = *it;
907 }
908 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700909}
910
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700912 const webrtc::RtpExtension& ext_to_match,
913 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700914 // We assume that all URIs are given in a canonical format.
915 const webrtc::RtpExtension* found =
916 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
917 ext_to_match.uri);
918 if (!found) {
919 return false;
920 }
921 if (found_extension) {
922 *found_extension = *found;
923 }
924 return true;
925}
926
927static bool FindByUriWithEncryptionPreference(
928 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200929 const webrtc::RtpExtension& ext_to_match,
930 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700931 webrtc::RtpExtension* found_extension) {
932 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700933 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700935 if (extension.uri == ext_to_match.uri) {
936 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700937 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700938 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700939 }
940 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700942 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000943 }
944 }
jbauch5869f502017-06-29 12:31:36 -0700945 if (unencrypted_extension) {
946 if (found_extension) {
947 *found_extension = *unencrypted_extension;
948 }
949 return true;
950 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 return false;
952}
953
zhihuang1c378ed2017-08-17 14:10:50 -0700954// Adds all extensions from |reference_extensions| to |offered_extensions| that
955// don't already exist in |offered_extensions| and ensure the IDs don't
956// collide. If an extension is added, it's also added to |regular_extensions| or
957// |encrypted_extensions|, and if the extension is in |regular_extensions| or
958// |encrypted_extensions|, its ID is marked as used in |used_ids|.
959// |offered_extensions| is for either audio or video while |regular_extensions|
960// and |encrypted_extensions| are used for both audio and video. There could be
961// overlap between audio extensions and video extensions.
962static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
963 RtpHeaderExtensions* offered_extensions,
964 RtpHeaderExtensions* regular_extensions,
965 RtpHeaderExtensions* encrypted_extensions,
966 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -0700967 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -0700968 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
969 nullptr)) {
olka3c747662017-08-17 06:50:32 -0700970 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -0700971 if (reference_extension.encrypt) {
972 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
973 &existing)) {
974 offered_extensions->push_back(existing);
975 } else {
976 used_ids->FindAndSetIdUsed(&reference_extension);
977 encrypted_extensions->push_back(reference_extension);
978 offered_extensions->push_back(reference_extension);
979 }
olka3c747662017-08-17 06:50:32 -0700980 } else {
zhihuang1c378ed2017-08-17 14:10:50 -0700981 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
982 &existing)) {
983 offered_extensions->push_back(existing);
984 } else {
985 used_ids->FindAndSetIdUsed(&reference_extension);
986 regular_extensions->push_back(reference_extension);
987 offered_extensions->push_back(reference_extension);
988 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000989 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 }
991 }
992}
993
jbauch5869f502017-06-29 12:31:36 -0700994static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
995 RtpHeaderExtensions* all_extensions,
996 UsedRtpHeaderExtensionIds* used_ids) {
997 RtpHeaderExtensions encrypted_extensions;
998 for (const webrtc::RtpExtension& extension : *extensions) {
999 webrtc::RtpExtension existing;
1000 // Don't add encrypted extensions again that were already included in a
1001 // previous offer or regular extensions that are also included as encrypted
1002 // extensions.
1003 if (extension.encrypt ||
1004 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1005 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001006 &existing) &&
1007 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001008 continue;
1009 }
1010
1011 if (FindByUri(*all_extensions, extension, &existing)) {
1012 encrypted_extensions.push_back(existing);
1013 } else {
1014 webrtc::RtpExtension encrypted(extension);
1015 encrypted.encrypt = true;
1016 used_ids->FindAndSetIdUsed(&encrypted);
1017 all_extensions->push_back(encrypted);
1018 encrypted_extensions.push_back(encrypted);
1019 }
1020 }
1021 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001022 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001023}
1024
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025static void NegotiateRtpHeaderExtensions(
1026 const RtpHeaderExtensions& local_extensions,
1027 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001028 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001030 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001031 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001032 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001033 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001034 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 // We respond with their RTP header extension id.
1036 negotiated_extenstions->push_back(theirs);
1037 }
1038 }
1039}
1040
1041static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001042 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1043 [](const AudioCodec& codec) {
1044 return STR_CASE_CMP(
1045 codec.name.c_str(),
1046 kComfortNoiseCodecName) == 0;
1047 }),
1048 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049}
1050
zhihuang1c378ed2017-08-17 14:10:50 -07001051// Create a media content to be answered for the given |sender_options|
1052// according to the given session_options.rtcp_mux, session_options.streams,
1053// codecs, crypto, and current_streams. If we don't currently have crypto (in
1054// current_cryptos) and it is enabled (in secure_policy), crypto is created
1055// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1056// negotiated with the offer. If the negotiation fails, this method returns
1057// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058template <class C>
1059static bool CreateMediaContentAnswer(
1060 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001061 const MediaDescriptionOptions& media_description_options,
1062 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001064 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065 const CryptoParamsVec* current_cryptos,
1066 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001067 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 bool bundle_enabled,
1070 MediaContentDescriptionImpl<C>* answer) {
1071 std::vector<C> negotiated_codecs;
1072 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1073 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001075
1076 answer->set_mixed_one_two_byte_header_extensions_supported(
1077 offer->mixed_one_two_byte_header_extensions_supported());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001079 NegotiateRtpHeaderExtensions(
1080 local_rtp_extenstions, offer->rtp_header_extensions(),
1081 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1083
zhihuang1c378ed2017-08-17 14:10:50 -07001084 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001085 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1086 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1087 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088
1089 if (sdes_policy != SEC_DISABLED) {
1090 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001091 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1092 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 if (current_cryptos) {
1094 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1095 }
1096 answer->AddCrypto(crypto);
1097 }
1098 }
1099
deadbeef7af91dd2016-12-13 11:29:11 -08001100 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001101 return false;
1102 }
1103
zhihuang1c378ed2017-08-17 14:10:50 -07001104 if (!AddStreamParams(media_description_options.sender_options,
1105 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106 return false; // Something went seriously wrong.
1107 }
1108
Steve Anton4e70a722017-11-28 14:57:10 -08001109 answer->set_direction(NegotiateRtpTransceiverDirection(
1110 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 return true;
1112}
1113
1114static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001115 const std::string& protocol,
1116 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001117 // Since not all applications serialize and deserialize the media protocol,
1118 // we will have to accept |protocol| to be empty.
1119 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001120 return true;
1121 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001122
zhihuangcf5b37c2016-05-05 11:44:35 -07001123 if (type == MEDIA_TYPE_DATA) {
1124 // Check for SCTP, but also for RTP for RTP-based data channels.
1125 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1126 if (secure_transport) {
1127 // Most likely scenarios first.
1128 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1129 IsPlainRtp(protocol);
1130 } else {
1131 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1132 }
1133 }
1134
1135 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1136 // JSEP specifies.
1137 if (secure_transport) {
1138 // Most likely scenarios first.
1139 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1140 } else {
1141 return IsPlainRtp(protocol);
1142 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143}
1144
1145static void SetMediaProtocol(bool secure_transport,
1146 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001147 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001149 else if (secure_transport)
1150 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151 else
1152 desc->set_protocol(kMediaProtocolAvpf);
1153}
1154
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001155// Gets the TransportInfo of the given |content_name| from the
1156// |current_description|. If doesn't exist, returns a new one.
1157static const TransportDescription* GetTransportDescription(
1158 const std::string& content_name,
1159 const SessionDescription* current_description) {
1160 const TransportDescription* desc = NULL;
1161 if (current_description) {
1162 const TransportInfo* info =
1163 current_description->GetTransportInfoByName(content_name);
1164 if (info) {
1165 desc = &info->description;
1166 }
1167 }
1168 return desc;
1169}
1170
1171// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001172static bool IsDtlsActive(const ContentInfo* content,
1173 const SessionDescription* current_description) {
1174 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001175 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001176 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001177
zhihuang1c378ed2017-08-17 14:10:50 -07001178 size_t msection_index = content - &current_description->contents()[0];
1179
1180 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001181 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001182 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001183
zhihuang1c378ed2017-08-17 14:10:50 -07001184 return current_description->transport_infos()[msection_index]
1185 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001186}
1187
Steve Anton8ffb9c32017-08-31 15:45:38 -07001188void MediaDescriptionOptions::AddAudioSender(
1189 const std::string& track_id,
1190 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001191 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001192 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001193}
1194
Steve Anton8ffb9c32017-08-31 15:45:38 -07001195void MediaDescriptionOptions::AddVideoSender(
1196 const std::string& track_id,
1197 const std::vector<std::string>& stream_ids,
1198 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001199 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001200 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001201}
1202
zhihuang1c378ed2017-08-17 14:10:50 -07001203void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1204 const std::string& stream_id) {
1205 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001206 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1207 // than one stream?
1208 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209}
1210
Steve Anton8ffb9c32017-08-31 15:45:38 -07001211void MediaDescriptionOptions::AddSenderInternal(
1212 const std::string& track_id,
1213 const std::vector<std::string>& stream_ids,
1214 int num_sim_layers) {
1215 // TODO(steveanton): Support any number of stream ids.
1216 RTC_CHECK(stream_ids.size() == 1U);
1217 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218}
1219
zhihuang1c378ed2017-08-17 14:10:50 -07001220bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1221 return std::find_if(media_description_options.begin(),
1222 media_description_options.end(),
1223 [type](const MediaDescriptionOptions& t) {
1224 return t.type == type;
1225 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001226}
1227
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1229 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001230 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231
1232MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1233 ChannelManager* channel_manager,
1234 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001235 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001236 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1237 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001239 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1241 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001242 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001243}
1244
ossudedfd282016-06-14 07:12:39 -07001245const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1246 const {
ossu075af922016-06-14 03:29:38 -07001247 return audio_sendrecv_codecs_;
1248}
1249
1250const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1251 return audio_send_codecs_;
1252}
1253
1254const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1255 return audio_recv_codecs_;
1256}
1257
1258void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001259 const AudioCodecs& send_codecs,
1260 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001261 audio_send_codecs_ = send_codecs;
1262 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001263 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264}
1265
1266SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001267 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001269 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001271 IceCredentialsIterator ice_credentials(
1272 session_options.pooled_ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001273 StreamParamsVec current_streams;
1274 GetCurrentStreamParams(current_description, &current_streams);
1275
zhihuang1c378ed2017-08-17 14:10:50 -07001276 AudioCodecs offer_audio_codecs;
1277 VideoCodecs offer_video_codecs;
1278 DataCodecs offer_data_codecs;
1279 GetCodecsForOffer(current_description, &offer_audio_codecs,
1280 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001281
zhihuang1c378ed2017-08-17 14:10:50 -07001282 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001284 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285 }
zhihuang1c378ed2017-08-17 14:10:50 -07001286 FilterDataCodecs(&offer_data_codecs,
1287 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001288
1289 RtpHeaderExtensions audio_rtp_extensions;
1290 RtpHeaderExtensions video_rtp_extensions;
Steve Anton1b8773d2018-04-06 11:13:34 -07001291 GetRtpHdrExtsToOffer(session_options, current_description,
1292 &audio_rtp_extensions, &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293
zhihuang1c378ed2017-08-17 14:10:50 -07001294 // Must have options for each existing section.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001295 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001296 RTC_DCHECK(current_description->contents().size() <=
1297 session_options.media_description_options.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001299
zhihuang1c378ed2017-08-17 14:10:50 -07001300 // Iterate through the media description options, matching with existing media
1301 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001302 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001303 for (const MediaDescriptionOptions& media_description_options :
1304 session_options.media_description_options) {
1305 const ContentInfo* current_content = nullptr;
1306 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001307 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001308 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001309 // Media type must match unless this media section is being recycled.
1310 RTC_DCHECK(current_content->rejected ||
1311 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001312 media_description_options.type));
1313 }
1314 switch (media_description_options.type) {
1315 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001316 if (!AddAudioContentForOffer(
1317 media_description_options, session_options, current_content,
1318 current_description, audio_rtp_extensions, offer_audio_codecs,
1319 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001320 return nullptr;
1321 }
1322 break;
1323 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001324 if (!AddVideoContentForOffer(
1325 media_description_options, session_options, current_content,
1326 current_description, video_rtp_extensions, offer_video_codecs,
1327 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001328 return nullptr;
1329 }
1330 break;
1331 case MEDIA_TYPE_DATA:
1332 if (!AddDataContentForOffer(media_description_options, session_options,
1333 current_content, current_description,
1334 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001335 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001336 return nullptr;
1337 }
1338 break;
1339 default:
1340 RTC_NOTREACHED();
1341 }
1342 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001343 }
1344
1345 // Bundle the contents together, if we've been asked to do so, and update any
1346 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001347 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001349 for (const ContentInfo& content : offer->contents()) {
1350 // TODO(deadbeef): There are conditions that make bundling two media
1351 // descriptions together illegal. For example, they use the same payload
1352 // type to represent different codecs, or same IDs for different header
1353 // extensions. We need to detect this and not try to bundle those media
1354 // descriptions together.
1355 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001356 }
1357 offer->AddGroup(offer_bundle);
1358 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001359 RTC_LOG(LS_ERROR)
1360 << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001361 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 }
1363 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001364 RTC_LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001365 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001366 }
1367 }
Steve Antone831b8c2018-02-01 12:22:16 -08001368
1369 // The following determines how to signal MSIDs to ensure compatibility with
1370 // older endpoints (in particular, older Plan B endpoints).
1371 if (session_options.is_unified_plan) {
1372 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1373 // Plan answerers will look at a=msid and Plan B answerers will look at the
1374 // a=ssrc MSID line.
1375 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1376 cricket::kMsidSignalingSsrcAttribute);
1377 } else {
1378 // Plan B always signals MSID using a=ssrc lines.
1379 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1380 }
1381
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382 return offer.release();
1383}
1384
1385SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001386 const SessionDescription* offer,
1387 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001388 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001389 if (!offer) {
1390 return nullptr;
1391 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001392
1393 IceCredentialsIterator ice_credentials(
1394 session_options.pooled_ice_credentials);
1395
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001396 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001397 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1398 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001399 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001400
1401 StreamParamsVec current_streams;
1402 GetCurrentStreamParams(current_description, &current_streams);
1403
deadbeefb7892532017-02-22 19:35:18 -08001404 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1405 // group in the answer with the appropriate content names.
1406 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1407 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1408 // Transport info shared by the bundle group.
1409 std::unique_ptr<TransportInfo> bundle_transport;
1410
Johannes Kron0854eb62018-10-10 22:33:20 +02001411 answer->set_mixed_one_two_byte_header_extensions_supported(
1412 offer->mixed_one_two_byte_header_extensions_supported());
1413
zhihuang1c378ed2017-08-17 14:10:50 -07001414 // Get list of all possible codecs that respects existing payload type
1415 // mappings and uses a single payload type space.
1416 //
1417 // Note that these lists may be further filtered for each m= section; this
1418 // step is done just to establish the payload type mappings shared by all
1419 // sections.
1420 AudioCodecs answer_audio_codecs;
1421 VideoCodecs answer_video_codecs;
1422 DataCodecs answer_data_codecs;
1423 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
1424 &answer_video_codecs, &answer_data_codecs);
1425
1426 if (!session_options.vad_enabled) {
1427 // If application doesn't want CN codecs in answer.
1428 StripCNCodecs(&answer_audio_codecs);
1429 }
1430 FilterDataCodecs(&answer_data_codecs,
1431 session_options.data_channel_type == DCT_SCTP);
1432
1433 // Must have options for exactly as many sections as in the offer.
1434 RTC_DCHECK(offer->contents().size() ==
1435 session_options.media_description_options.size());
1436 // Iterate through the media description options, matching with existing
1437 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001438 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001439 for (const MediaDescriptionOptions& media_description_options :
1440 session_options.media_description_options) {
1441 const ContentInfo* offer_content = &offer->contents()[msection_index];
1442 // Media types and MIDs must match between the remote offer and the
1443 // MediaDescriptionOptions.
1444 RTC_DCHECK(
1445 IsMediaContentOfType(offer_content, media_description_options.type));
1446 RTC_DCHECK(media_description_options.mid == offer_content->name);
1447 const ContentInfo* current_content = nullptr;
1448 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001449 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001450 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001451 }
zhihuang1c378ed2017-08-17 14:10:50 -07001452 switch (media_description_options.type) {
1453 case MEDIA_TYPE_AUDIO:
1454 if (!AddAudioContentForAnswer(
1455 media_description_options, session_options, offer_content,
1456 offer, current_content, current_description,
1457 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001458 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001459 return nullptr;
1460 }
1461 break;
1462 case MEDIA_TYPE_VIDEO:
1463 if (!AddVideoContentForAnswer(
1464 media_description_options, session_options, offer_content,
1465 offer, current_content, current_description,
1466 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001467 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001468 return nullptr;
1469 }
1470 break;
1471 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001472 if (!AddDataContentForAnswer(
1473 media_description_options, session_options, offer_content,
1474 offer, current_content, current_description,
1475 bundle_transport.get(), answer_data_codecs, &current_streams,
1476 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001477 return nullptr;
1478 }
1479 break;
1480 default:
1481 RTC_NOTREACHED();
1482 }
1483 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001484 // See if we can add the newly generated m= section to the BUNDLE group in
1485 // the answer.
1486 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001487 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001488 offer_bundle->HasContentName(added.name)) {
1489 answer_bundle.AddContentName(added.name);
1490 bundle_transport.reset(
1491 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001493 }
1494
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001495 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1496 // it's empty. RFC5888 says:
1497 //
1498 // A SIP entity that receives an offer that contains an "a=group" line
1499 // with semantics that are understood MUST return an answer that
1500 // contains an "a=group" line with the same semantics.
1501 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001502 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001503 }
deadbeefb7892532017-02-22 19:35:18 -08001504
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001505 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001506 // Share the same ICE credentials and crypto params across all contents,
1507 // as BUNDLE requires.
1508 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001509 RTC_LOG(LS_ERROR)
1510 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001511 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001513
deadbeefb7892532017-02-22 19:35:18 -08001514 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001515 RTC_LOG(LS_ERROR)
1516 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001517 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 }
1519 }
1520
Steve Antone831b8c2018-02-01 12:22:16 -08001521 // The following determines how to signal MSIDs to ensure compatibility with
1522 // older endpoints (in particular, older Plan B endpoints).
1523 if (session_options.is_unified_plan) {
1524 // Unified Plan needs to look at what the offer included to find the most
1525 // compatible answer.
1526 if (offer->msid_signaling() == 0) {
1527 // We end up here in one of three cases:
1528 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1529 // matter what we pick here.
1530 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1531 // it also doesn't matter what we pick here.
1532 // 3. Media that's either sendonly or inactive from the remote endpoint.
1533 // We don't have any information to say whether the endpoint is Plan B
1534 // or Unified Plan, so be conservative and send both.
1535 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1536 cricket::kMsidSignalingSsrcAttribute);
1537 } else if (offer->msid_signaling() ==
1538 (cricket::kMsidSignalingMediaSection |
1539 cricket::kMsidSignalingSsrcAttribute)) {
1540 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1541 // probably talking to a Unified Plan endpoint so respond with just
1542 // a=msid.
1543 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1544 } else {
1545 // Otherwise, it's clear which method the offerer is using so repeat that
1546 // back to them.
1547 answer->set_msid_signaling(offer->msid_signaling());
1548 }
1549 } else {
1550 // Plan B always signals MSID using a=ssrc lines.
1551 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1552 }
1553
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554 return answer.release();
1555}
1556
ossu075af922016-06-14 03:29:38 -07001557const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1558 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001559 switch (direction) {
1560 // If stream is inactive - generate list as if sendrecv.
1561 case RtpTransceiverDirection::kSendRecv:
1562 case RtpTransceiverDirection::kInactive:
1563 return audio_sendrecv_codecs_;
1564 case RtpTransceiverDirection::kSendOnly:
1565 return audio_send_codecs_;
1566 case RtpTransceiverDirection::kRecvOnly:
1567 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001568 }
Steve Anton1d03a752017-11-27 14:30:09 -08001569 RTC_NOTREACHED();
1570 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001571}
1572
1573const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1574 const RtpTransceiverDirection& offer,
1575 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001576 switch (answer) {
1577 // For inactive and sendrecv answers, generate lists as if we were to accept
1578 // the offer's direction. See RFC 3264 Section 6.1.
1579 case RtpTransceiverDirection::kSendRecv:
1580 case RtpTransceiverDirection::kInactive:
1581 return GetAudioCodecsForOffer(
1582 webrtc::RtpTransceiverDirectionReversed(offer));
1583 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001584 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001585 case RtpTransceiverDirection::kRecvOnly:
1586 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001587 }
Steve Anton1d03a752017-11-27 14:30:09 -08001588 RTC_NOTREACHED();
1589 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001590}
1591
zhihuang1c378ed2017-08-17 14:10:50 -07001592void MergeCodecsFromDescription(const SessionDescription* description,
1593 AudioCodecs* audio_codecs,
1594 VideoCodecs* video_codecs,
1595 DataCodecs* data_codecs,
1596 UsedPayloadTypes* used_pltypes) {
1597 RTC_DCHECK(description);
1598 for (const ContentInfo& content : description->contents()) {
1599 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1600 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001601 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001602 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1603 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1604 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001605 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001606 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1607 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1608 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001609 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001610 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1611 }
1612 }
1613}
1614
1615// Getting codecs for an offer involves these steps:
1616//
1617// 1. Construct payload type -> codec mappings for current description.
1618// 2. Add any reference codecs that weren't already present
1619// 3. For each individual media description (m= section), filter codecs based
1620// on the directional attribute (happens in another method).
1621void MediaSessionDescriptionFactory::GetCodecsForOffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 const SessionDescription* current_description,
1623 AudioCodecs* audio_codecs,
1624 VideoCodecs* video_codecs,
1625 DataCodecs* data_codecs) const {
1626 UsedPayloadTypes used_pltypes;
1627 audio_codecs->clear();
1628 video_codecs->clear();
1629 data_codecs->clear();
1630
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001632 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1633 // new media type is added.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001635 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1636 data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637 }
1638
1639 // Add our codecs that are not in |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001640 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1641 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1642 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1643}
1644
1645// Getting codecs for an answer involves these steps:
1646//
1647// 1. Construct payload type -> codec mappings for current description.
1648// 2. Add any codecs from the offer that weren't already present.
1649// 3. Add any remaining codecs that weren't already present.
1650// 4. For each individual media description (m= section), filter codecs based
1651// on the directional attribute (happens in another method).
1652void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1653 const SessionDescription* current_description,
1654 const SessionDescription* remote_offer,
1655 AudioCodecs* audio_codecs,
1656 VideoCodecs* video_codecs,
1657 DataCodecs* data_codecs) const {
1658 UsedPayloadTypes used_pltypes;
1659 audio_codecs->clear();
1660 video_codecs->clear();
1661 data_codecs->clear();
1662
1663 // First - get all codecs from the current description if the media type
1664 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1665 // new media type is added.
1666 if (current_description) {
1667 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1668 data_codecs, &used_pltypes);
1669 }
1670
1671 // Second - filter out codecs that we don't support at all and should ignore.
1672 AudioCodecs filtered_offered_audio_codecs;
1673 VideoCodecs filtered_offered_video_codecs;
1674 DataCodecs filtered_offered_data_codecs;
1675 for (const ContentInfo& content : remote_offer->contents()) {
1676 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1677 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001678 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001679 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1680 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1681 filtered_offered_audio_codecs,
1682 offered_audio_codec, nullptr) &&
1683 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1684 offered_audio_codec, nullptr)) {
1685 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1686 }
1687 }
1688 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1689 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001690 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001691 for (const VideoCodec& offered_video_codec : video->codecs()) {
1692 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1693 filtered_offered_video_codecs,
1694 offered_video_codec, nullptr) &&
1695 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1696 offered_video_codec, nullptr)) {
1697 filtered_offered_video_codecs.push_back(offered_video_codec);
1698 }
1699 }
1700 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1701 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001702 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001703 for (const DataCodec& offered_data_codec : data->codecs()) {
1704 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1705 filtered_offered_data_codecs,
1706 offered_data_codec, nullptr) &&
1707 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1708 offered_data_codec, nullptr)) {
1709 filtered_offered_data_codecs.push_back(offered_data_codec);
1710 }
1711 }
1712 }
1713 }
1714
1715 // Add codecs that are not in |current_description| but were in
1716 // |remote_offer|.
1717 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1718 &used_pltypes);
1719 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1720 &used_pltypes);
1721 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1722 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001723}
1724
1725void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton1b8773d2018-04-06 11:13:34 -07001726 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001728 RtpHeaderExtensions* offer_audio_extensions,
1729 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001730 // All header extensions allocated from the same range to avoid potential
1731 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001733 RtpHeaderExtensions all_regular_extensions;
1734 RtpHeaderExtensions all_encrypted_extensions;
zhihuang1c378ed2017-08-17 14:10:50 -07001735 offer_audio_extensions->clear();
1736 offer_video_extensions->clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001737
1738 // First - get all extensions from the current description if the media type
1739 // is used.
1740 // Add them to |used_ids| so the local ids are not reused if a new media
1741 // type is added.
1742 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001743 for (const ContentInfo& content : current_description->contents()) {
1744 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1745 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001746 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001747 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1748 &all_regular_extensions, &all_encrypted_extensions,
1749 &used_ids);
1750 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1751 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001752 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001753 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1754 &all_regular_extensions, &all_encrypted_extensions,
1755 &used_ids);
1756 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001757 }
1758 }
1759
1760 // Add our default RTP header extensions that are not in
1761 // |current_description|.
Steve Anton1b8773d2018-04-06 11:13:34 -07001762 MergeRtpHdrExts(audio_rtp_header_extensions(session_options.is_unified_plan),
1763 offer_audio_extensions, &all_regular_extensions,
1764 &all_encrypted_extensions, &used_ids);
1765 MergeRtpHdrExts(video_rtp_header_extensions(session_options.is_unified_plan),
1766 offer_video_extensions, &all_regular_extensions,
1767 &all_encrypted_extensions, &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001768
jbauch5869f502017-06-29 12:31:36 -07001769 // TODO(jbauch): Support adding encrypted header extensions to existing
1770 // sessions.
1771 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001772 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1773 &all_encrypted_extensions, &used_ids);
1774 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1775 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001776 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777}
1778
1779bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001780 const std::string& content_name,
1781 const TransportOptions& transport_options,
1782 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001783 SessionDescription* offer_desc,
1784 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001786 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 const TransportDescription* current_tdesc =
1788 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001789 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001790 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1791 ice_credentials));
Yves Gerey665174f2018-06-19 15:03:05 +02001792 bool ret =
1793 (new_tdesc.get() != NULL &&
1794 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 if (!ret) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001796 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1797 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798 }
1799 return ret;
1800}
1801
1802TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1803 const std::string& content_name,
1804 const SessionDescription* offer_desc,
1805 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001806 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001807 bool require_transport_attributes,
1808 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 if (!transport_desc_factory_)
1810 return NULL;
1811 const TransportDescription* offer_tdesc =
1812 GetTransportDescription(content_name, offer_desc);
1813 const TransportDescription* current_tdesc =
1814 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001815 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1816 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001817 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001818}
1819
1820bool MediaSessionDescriptionFactory::AddTransportAnswer(
1821 const std::string& content_name,
1822 const TransportDescription& transport_desc,
1823 SessionDescription* answer_desc) const {
Yves Gerey665174f2018-06-19 15:03:05 +02001824 if (!answer_desc->AddTransportInfo(
1825 TransportInfo(content_name, transport_desc))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001826 RTC_LOG(LS_ERROR) << "Failed to AddTransportAnswer, content name="
1827 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001828 return false;
1829 }
1830 return true;
1831}
1832
zhihuang1c378ed2017-08-17 14:10:50 -07001833// |audio_codecs| = set of all possible codecs that can be used, with correct
1834// payload type mappings
1835//
1836// |supported_audio_codecs| = set of codecs that are supported for the direction
1837// of this m= section
1838//
1839// acd->codecs() = set of previously negotiated codecs for this m= section
1840//
1841// The payload types should come from audio_codecs, but the order should come
1842// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1843// change existing codec priority, and that new codecs are added with the right
1844// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001845bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001846 const MediaDescriptionOptions& media_description_options,
1847 const MediaSessionOptions& session_options,
1848 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001849 const SessionDescription* current_description,
1850 const RtpHeaderExtensions& audio_rtp_extensions,
1851 const AudioCodecs& audio_codecs,
1852 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001853 SessionDescription* desc,
1854 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001855 // Filter audio_codecs (which includes all codecs, with correctly remapped
1856 // payload types) based on transceiver direction.
1857 const AudioCodecs& supported_audio_codecs =
1858 GetAudioCodecsForOffer(media_description_options.direction);
1859
1860 AudioCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08001861 // Add the codecs from current content if it exists and is not being recycled.
1862 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001863 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001864 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001865 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001866 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001867 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1868 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001869 filtered_codecs.push_back(codec);
1870 }
1871 }
1872 }
1873 // Add other supported audio codecs.
1874 AudioCodec found_codec;
1875 for (const AudioCodec& codec : supported_audio_codecs) {
1876 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1877 codec, &found_codec) &&
1878 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1879 codec, nullptr)) {
1880 // Use the |found_codec| from |audio_codecs| because it has the correctly
1881 // mapped payload type.
1882 filtered_codecs.push_back(found_codec);
1883 }
1884 }
deadbeef44f08192015-12-15 16:20:09 -08001885
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001886 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001887 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1888 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001889
kwiberg31022942016-03-11 14:18:21 -08001890 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001891 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001892 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1893 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001894 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001895 media_description_options.sender_options, session_options,
1896 filtered_codecs, sdes_policy, GetCryptos(current_content),
1897 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001898 return false;
1899 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001900
1901 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1902 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001903
Steve Anton4e70a722017-11-28 14:57:10 -08001904 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001905
Steve Anton5adfafd2017-12-20 16:34:00 -08001906 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001907 media_description_options.stopped, audio.release());
1908 if (!AddTransportOffer(media_description_options.mid,
1909 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001910 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001911 return false;
1912 }
1913
1914 return true;
1915}
1916
1917bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001918 const MediaDescriptionOptions& media_description_options,
1919 const MediaSessionOptions& session_options,
1920 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001921 const SessionDescription* current_description,
1922 const RtpHeaderExtensions& video_rtp_extensions,
1923 const VideoCodecs& video_codecs,
1924 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001925 SessionDescription* desc,
1926 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001927 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001928 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1929 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001930
kwiberg31022942016-03-11 14:18:21 -08001931 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001932 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001933 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1934 &crypto_suites);
1935
1936 VideoCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08001937 // Add the codecs from current content if it exists and is not being recycled.
1938 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001939 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07001940 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001941 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001942 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001943 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07001944 nullptr)) {
1945 filtered_codecs.push_back(codec);
1946 }
1947 }
1948 }
1949 // Add other supported video codecs.
1950 VideoCodec found_codec;
1951 for (const VideoCodec& codec : video_codecs_) {
1952 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1953 &found_codec) &&
1954 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1955 nullptr)) {
1956 // Use the |found_codec| from |video_codecs| because it has the correctly
1957 // mapped payload type.
1958 filtered_codecs.push_back(found_codec);
1959 }
1960 }
1961
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001962 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001963 media_description_options.sender_options, session_options,
1964 filtered_codecs, sdes_policy, GetCryptos(current_content),
1965 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001966 return false;
1967 }
1968
zhihuang1c378ed2017-08-17 14:10:50 -07001969 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001970
1971 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1972 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001973
Steve Anton4e70a722017-11-28 14:57:10 -08001974 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001975
Steve Anton5adfafd2017-12-20 16:34:00 -08001976 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001977 media_description_options.stopped, video.release());
1978 if (!AddTransportOffer(media_description_options.mid,
1979 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001980 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001981 return false;
1982 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001983 return true;
1984}
1985
1986bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001987 const MediaDescriptionOptions& media_description_options,
1988 const MediaSessionOptions& session_options,
1989 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001990 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001991 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001992 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001993 SessionDescription* desc,
1994 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001995 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1996
kwiberg31022942016-03-11 14:18:21 -08001997 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07001998 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
1999 // If the DataChannel type is not specified, use the DataChannel type in
2000 // the current description.
2001 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002002 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002003 is_sctp = (current_content->media_description()->protocol() ==
2004 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002005 }
deadbeef44f08192015-12-15 16:20:09 -08002006
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002007 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002008 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2009 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002010 std::vector<std::string> crypto_suites;
2011 if (is_sctp) {
2012 // SDES doesn't make sense for SCTP, so we disable it, and we only
2013 // get SDES crypto suites for RTP-based data channels.
2014 sdes_policy = cricket::SEC_DISABLED;
2015 // Unlike SetMediaProtocol below, we need to set the protocol
2016 // before we call CreateMediaContentOffer. Otherwise,
2017 // CreateMediaContentOffer won't know this is SCTP and will
2018 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002019 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2020 // it's safe to do so. Older versions of webrtc would reject these
2021 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002022 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2023 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002024 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002025 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002026 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002027 }
2028
zhihuang1c378ed2017-08-17 14:10:50 -07002029 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002030 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002031 media_description_options.sender_options, session_options,
2032 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2033 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002034 return false;
2035 }
2036
2037 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002038 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002039 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002040 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002041 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002043 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002044 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002045 }
zhihuang1c378ed2017-08-17 14:10:50 -07002046 if (!AddTransportOffer(media_description_options.mid,
2047 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002048 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002049 return false;
2050 }
2051 return true;
2052}
2053
zhihuang1c378ed2017-08-17 14:10:50 -07002054// |audio_codecs| = set of all possible codecs that can be used, with correct
2055// payload type mappings
2056//
2057// |supported_audio_codecs| = set of codecs that are supported for the direction
2058// of this m= section
2059//
2060// acd->codecs() = set of previously negotiated codecs for this m= section
2061//
2062// The payload types should come from audio_codecs, but the order should come
2063// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2064// change existing codec priority, and that new codecs are added with the right
2065// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002066bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002067 const MediaDescriptionOptions& media_description_options,
2068 const MediaSessionOptions& session_options,
2069 const ContentInfo* offer_content,
2070 const SessionDescription* offer_description,
2071 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002072 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002073 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002074 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002075 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002076 SessionDescription* answer,
2077 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002078 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002079 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002080 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002081
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002082 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
2083 media_description_options.mid, offer_description,
2084 media_description_options.transport_options, current_description,
2085 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002086 if (!audio_transport) {
2087 return false;
2088 }
2089
zhihuang1c378ed2017-08-17 14:10:50 -07002090 // Pick codecs based on the requested communications direction in the offer
2091 // and the selected direction in the answer.
2092 // Note these will be filtered one final time in CreateMediaContentAnswer.
2093 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002094 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002095 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002096 AudioCodecs supported_audio_codecs =
2097 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2098
2099 AudioCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08002100 // Add the codecs from current content if it exists and is not being recycled.
2101 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002102 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002103 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002104 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002105 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002106 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2107 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002108 filtered_codecs.push_back(codec);
2109 }
2110 }
2111 }
2112 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002113 for (const AudioCodec& codec : supported_audio_codecs) {
2114 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002115 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002116 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2117 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002118 // We should use the local codec with local parameters and the codec id
2119 // would be correctly mapped in |NegotiateCodecs|.
2120 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002121 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002122 }
2123
zhihuang1c378ed2017-08-17 14:10:50 -07002124 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2125 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002126 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002127 new AudioContentDescription());
2128 // Do not require or create SDES cryptos if DTLS is used.
2129 cricket::SecurePolicy sdes_policy =
2130 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2131 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002132 offer_audio_description, media_description_options, session_options,
2133 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton1b8773d2018-04-06 11:13:34 -07002134 audio_rtp_header_extensions(session_options.is_unified_plan),
2135 enable_encrypted_rtp_header_extensions_, current_streams,
2136 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002137 return false; // Fails the session setup.
2138 }
2139
deadbeefb7892532017-02-22 19:35:18 -08002140 bool secure = bundle_transport ? bundle_transport->description.secure()
2141 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002142 bool rejected = media_description_options.stopped ||
2143 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002144 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2145 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002146 if (!AddTransportAnswer(media_description_options.mid,
2147 *(audio_transport.get()), answer)) {
2148 return false;
2149 }
2150
2151 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002152 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2153 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002154 }
2155
zhihuang1c378ed2017-08-17 14:10:50 -07002156 answer->AddContent(media_description_options.mid, offer_content->type,
2157 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002158 return true;
2159}
2160
2161bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002162 const MediaDescriptionOptions& media_description_options,
2163 const MediaSessionOptions& session_options,
2164 const ContentInfo* offer_content,
2165 const SessionDescription* offer_description,
2166 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002167 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002168 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002169 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002170 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002171 SessionDescription* answer,
2172 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002173 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002174 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002175 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002176
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002177 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer(
2178 media_description_options.mid, offer_description,
2179 media_description_options.transport_options, current_description,
2180 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002181 if (!video_transport) {
2182 return false;
2183 }
2184
zhihuang1c378ed2017-08-17 14:10:50 -07002185 VideoCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08002186 // Add the codecs from current content if it exists and is not being recycled.
2187 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002188 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002189 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002190 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002191 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002192 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002193 nullptr)) {
2194 filtered_codecs.push_back(codec);
2195 }
2196 }
2197 }
2198 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002199 for (const VideoCodec& codec : video_codecs_) {
2200 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002201 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002202 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2203 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002204 // We should use the local codec with local parameters and the codec id
2205 // would be correctly mapped in |NegotiateCodecs|.
2206 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002207 }
2208 }
2209
2210 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2211 session_options.bundle_enabled;
2212
kwiberg31022942016-03-11 14:18:21 -08002213 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002214 new VideoContentDescription());
2215 // Do not require or create SDES cryptos if DTLS is used.
2216 cricket::SecurePolicy sdes_policy =
2217 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002218 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002219 offer_video_description, media_description_options, session_options,
2220 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton1b8773d2018-04-06 11:13:34 -07002221 video_rtp_header_extensions(session_options.is_unified_plan),
2222 enable_encrypted_rtp_header_extensions_, current_streams,
2223 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002224 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002225 }
deadbeefb7892532017-02-22 19:35:18 -08002226 bool secure = bundle_transport ? bundle_transport->description.secure()
2227 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002228 bool rejected = media_description_options.stopped ||
2229 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002230 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2231 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002232 if (!AddTransportAnswer(media_description_options.mid,
2233 *(video_transport.get()), answer)) {
2234 return false;
2235 }
2236
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002237 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002238 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002239 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002240 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2241 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002242 }
zhihuang1c378ed2017-08-17 14:10:50 -07002243 answer->AddContent(media_description_options.mid, offer_content->type,
2244 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002245 return true;
2246}
2247
2248bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002249 const MediaDescriptionOptions& media_description_options,
2250 const MediaSessionOptions& session_options,
2251 const ContentInfo* offer_content,
2252 const SessionDescription* offer_description,
2253 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002254 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002255 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002256 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002257 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002258 SessionDescription* answer,
2259 IceCredentialsIterator* ice_credentials) const {
2260 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer(
2261 media_description_options.mid, offer_description,
2262 media_description_options.transport_options, current_description,
2263 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002264 if (!data_transport) {
2265 return false;
2266 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002267
kwiberg31022942016-03-11 14:18:21 -08002268 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002269 new DataContentDescription());
2270 // Do not require or create SDES cryptos if DTLS is used.
2271 cricket::SecurePolicy sdes_policy =
2272 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002273 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2274 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002275 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2276 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002277 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002278 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002279 offer_data_description, media_description_options, session_options,
2280 data_codecs, sdes_policy, GetCryptos(current_content),
2281 RtpHeaderExtensions(), enable_encrypted_rtp_header_extensions_,
2282 current_streams, bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002283 return false; // Fails the session setup.
2284 }
2285
zstein4b2e0822017-02-17 19:48:38 -08002286 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002287 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2288 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2289
deadbeefb7892532017-02-22 19:35:18 -08002290 bool secure = bundle_transport ? bundle_transport->description.secure()
2291 : data_transport->secure();
2292
zhihuang1c378ed2017-08-17 14:10:50 -07002293 bool rejected = session_options.data_channel_type == DCT_NONE ||
2294 media_description_options.stopped ||
2295 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002296 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2297 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002298 if (!AddTransportAnswer(media_description_options.mid,
2299 *(data_transport.get()), answer)) {
2300 return false;
2301 }
2302
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002303 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002304 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002305 } else {
2306 // RFC 3264
2307 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002308 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002309 }
zhihuang1c378ed2017-08-17 14:10:50 -07002310 answer->AddContent(media_description_options.mid, offer_content->type,
2311 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002312 return true;
2313}
2314
zhihuang1c378ed2017-08-17 14:10:50 -07002315void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2316 audio_sendrecv_codecs_.clear();
2317 all_audio_codecs_.clear();
2318 // Compute the audio codecs union.
2319 for (const AudioCodec& send : audio_send_codecs_) {
2320 all_audio_codecs_.push_back(send);
2321 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2322 send, nullptr)) {
2323 // It doesn't make sense to have an RTX codec we support sending but not
2324 // receiving.
2325 RTC_DCHECK(!IsRtxCodec(send));
2326 }
2327 }
2328 for (const AudioCodec& recv : audio_recv_codecs_) {
2329 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2330 recv, nullptr)) {
2331 all_audio_codecs_.push_back(recv);
2332 }
2333 }
2334 // Use NegotiateCodecs to merge our codec lists, since the operation is
2335 // essentially the same. Put send_codecs as the offered_codecs, which is the
2336 // order we'd like to follow. The reasoning is that encoding is usually more
2337 // expensive than decoding, and prioritizing a codec in the send list probably
2338 // means it's a codec we can handle efficiently.
2339 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2340 &audio_sendrecv_codecs_);
2341}
2342
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002344 return (content && (content->type == MediaProtocolType::kRtp ||
2345 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002346}
2347
2348bool IsAudioContent(const ContentInfo* content) {
2349 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2350}
2351
2352bool IsVideoContent(const ContentInfo* content) {
2353 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2354}
2355
2356bool IsDataContent(const ContentInfo* content) {
2357 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2358}
2359
deadbeef0ed85b22016-02-23 17:24:52 -08002360const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2361 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002362 for (const ContentInfo& content : contents) {
2363 if (IsMediaContentOfType(&content, media_type)) {
2364 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365 }
2366 }
deadbeef0ed85b22016-02-23 17:24:52 -08002367 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002368}
2369
2370const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2371 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2372}
2373
2374const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2375 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2376}
2377
2378const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2379 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2380}
2381
Steve Antonad7bffc2018-01-22 10:21:56 -08002382const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2383 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002384 if (sdesc == nullptr) {
2385 return nullptr;
2386 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387
2388 return GetFirstMediaContent(sdesc->contents(), media_type);
2389}
2390
2391const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2392 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2393}
2394
2395const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2396 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2397}
2398
2399const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2400 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2401}
2402
2403const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002404 const SessionDescription* sdesc,
2405 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002407 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002408}
2409
2410const AudioContentDescription* GetFirstAudioContentDescription(
2411 const SessionDescription* sdesc) {
2412 return static_cast<const AudioContentDescription*>(
2413 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2414}
2415
2416const VideoContentDescription* GetFirstVideoContentDescription(
2417 const SessionDescription* sdesc) {
2418 return static_cast<const VideoContentDescription*>(
2419 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2420}
2421
2422const DataContentDescription* GetFirstDataContentDescription(
2423 const SessionDescription* sdesc) {
2424 return static_cast<const DataContentDescription*>(
2425 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2426}
2427
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002428//
2429// Non-const versions of the above functions.
2430//
2431
Steve Anton36b29d12017-10-30 09:57:42 -07002432ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002433 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002434 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002435 if (IsMediaContentOfType(&content, media_type)) {
2436 return &content;
2437 }
2438 }
2439 return nullptr;
2440}
2441
Steve Anton36b29d12017-10-30 09:57:42 -07002442ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002443 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2444}
2445
Steve Anton36b29d12017-10-30 09:57:42 -07002446ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002447 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2448}
2449
Steve Anton36b29d12017-10-30 09:57:42 -07002450ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002451 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2452}
2453
Steve Antonad7bffc2018-01-22 10:21:56 -08002454ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2455 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002456 if (sdesc == nullptr) {
2457 return nullptr;
2458 }
2459
Steve Anton36b29d12017-10-30 09:57:42 -07002460 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002461}
2462
2463ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2464 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2465}
2466
2467ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2468 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2469}
2470
2471ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2472 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2473}
2474
2475MediaContentDescription* GetFirstMediaContentDescription(
2476 SessionDescription* sdesc,
2477 MediaType media_type) {
2478 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002479 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002480}
2481
2482AudioContentDescription* GetFirstAudioContentDescription(
2483 SessionDescription* sdesc) {
2484 return static_cast<AudioContentDescription*>(
2485 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2486}
2487
2488VideoContentDescription* GetFirstVideoContentDescription(
2489 SessionDescription* sdesc) {
2490 return static_cast<VideoContentDescription*>(
2491 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2492}
2493
2494DataContentDescription* GetFirstDataContentDescription(
2495 SessionDescription* sdesc) {
2496 return static_cast<DataContentDescription*>(
2497 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2498}
2499
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002500} // namespace cricket