blob: d186513e9bdf853df25c32a62f3b3f53e8136cc5 [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
Oleh Prypin8f4bc412018-10-11 21:10:39 +000042void GetSupportedSdesCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
43 std::vector<int>*),
44 const rtc::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.
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000198void GetSupportedAudioSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
199 std::vector<int>* crypto_suites) {
200 if (crypto_options.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700201 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
202 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
203 }
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000204 if (crypto_options.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700205 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
206 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800207 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208}
209
deadbeef7914b8c2017-04-21 03:23:33 -0700210void GetSupportedAudioSdesCryptoSuiteNames(
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000211 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800212 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700213 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
214 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215}
216
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000217void GetSupportedVideoSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
218 std::vector<int>* crypto_suites) {
219 if (crypto_options.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700220 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
221 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
222 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800223 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000224}
225
deadbeef7914b8c2017-04-21 03:23:33 -0700226void GetSupportedVideoSdesCryptoSuiteNames(
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000227 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800228 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700229 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
230 crypto_options, crypto_suite_names);
231}
232
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000233void GetSupportedDataSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
234 std::vector<int>* crypto_suites) {
235 if (crypto_options.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700236 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
237 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
238 }
239 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
240}
241
242void GetSupportedDataSdesCryptoSuiteNames(
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000243 const rtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700244 std::vector<std::string>* crypto_suite_names) {
245 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
246 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800247}
248
jbauchcb560652016-08-04 05:20:32 -0700249// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700250// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
251// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700252// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253static bool SelectCrypto(const MediaContentDescription* offer,
254 bool bundle,
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000255 const rtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700256 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
258 const CryptoParamsVec& cryptos = offer->cryptos();
259
Steve Anton3a66edf2018-09-10 12:57:37 -0700260 for (const CryptoParams& crypto : cryptos) {
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000261 if ((crypto_options.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700262 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
263 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
264 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Oleh Prypin8f4bc412018-10-11 21:10:39 +0000265 !bundle && crypto_options.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700266 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 }
268 }
269 return false;
270}
271
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000273// The generated values are added to |ssrcs|.
274// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000276 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200277 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000278 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200279 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000281 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000282 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
284 ssrcs->push_back(candidate);
285 }
286}
287
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288// Finds all StreamParams of all media types and attach them to stream_params.
289static void GetCurrentStreamParams(const SessionDescription* sdesc,
290 StreamParamsVec* stream_params) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800291 RTC_DCHECK(stream_params);
292 if (!sdesc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 return;
Steve Antonb1c1de12017-12-21 15:14:30 -0800294 }
295 for (const ContentInfo& content : sdesc->contents()) {
296 if (!content.media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 continue;
298 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800299 for (const StreamParams& params : content.media_description()->streams()) {
300 stream_params->push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 }
302 }
303}
304
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000305// Filters the data codecs for the data channel type.
306void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
307 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700308 const char* codec_name =
309 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700310 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
311 [&codec_name](const DataCodec& codec) {
312 return CodecNamesEq(codec.name, codec_name);
313 }),
314 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000315}
316
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317template <typename IdStruct>
318class UsedIds {
319 public:
320 UsedIds(int min_allowed_id, int max_allowed_id)
321 : min_allowed_id_(min_allowed_id),
322 max_allowed_id_(max_allowed_id),
Yves Gerey665174f2018-06-19 15:03:05 +0200323 next_id_(max_allowed_id) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324
325 // Loops through all Id in |ids| and changes its id if it is
326 // already in use by another IdStruct. Call this methods with all Id
327 // in a session description to make sure no duplicate ids exists.
328 // Note that typename Id must be a type of IdStruct.
329 template <typename Id>
330 void FindAndSetIdUsed(std::vector<Id>* ids) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700331 for (const Id& id : *ids) {
332 FindAndSetIdUsed(&id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
334 }
335
336 // Finds and sets an unused id if the |idstruct| id is already in use.
337 void FindAndSetIdUsed(IdStruct* idstruct) {
338 const int original_id = idstruct->id;
339 int new_id = idstruct->id;
340
341 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
342 // If the original id is not in range - this is an id that can't be
343 // dynamically changed.
344 return;
345 }
346
347 if (IsIdUsed(original_id)) {
348 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100349 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
350 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 idstruct->id = new_id;
352 }
353 SetIdUsed(new_id);
354 }
355
356 private:
357 // Returns the first unused id in reverse order.
358 // This hopefully reduce the risk of more collisions. We want to change the
359 // default ids as little as possible.
360 int FindUnusedId() {
361 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
362 --next_id_;
363 }
nisseede5da42017-01-12 05:15:36 -0800364 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 return next_id_;
366 }
367
Yves Gerey665174f2018-06-19 15:03:05 +0200368 bool IsIdUsed(int new_id) { return id_set_.find(new_id) != id_set_.end(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369
Yves Gerey665174f2018-06-19 15:03:05 +0200370 void SetIdUsed(int new_id) { id_set_.insert(new_id); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371
372 const int min_allowed_id_;
373 const int max_allowed_id_;
374 int next_id_;
375 std::set<int> id_set_;
376};
377
378// Helper class used for finding duplicate RTP payload types among audio, video
379// and data codecs. When bundle is used the payload types may not collide.
380class UsedPayloadTypes : public UsedIds<Codec> {
381 public:
382 UsedPayloadTypes()
Yves Gerey665174f2018-06-19 15:03:05 +0200383 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384
385 private:
386 static const int kDynamicPayloadTypeMin = 96;
387 static const int kDynamicPayloadTypeMax = 127;
388};
389
390// Helper class used for finding duplicate RTP Header extension ids among
Johannes Kron07ba2b92018-09-26 13:33:35 +0200391// audio and video extensions. Only applies to one-byte header extensions at the
392// moment. ids > 14 will always be reported as available.
393// TODO(kron): This class needs to be refactored when we start to send two-byte
394// header extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700395class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 public:
397 UsedRtpHeaderExtensionIds()
Johannes Kron07ba2b92018-09-26 13:33:35 +0200398 : UsedIds<webrtc::RtpExtension>(
399 webrtc::RtpExtension::kMinId,
400 webrtc::RtpExtension::kOneByteHeaderExtensionMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401
402 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403};
404
zhihuang1c378ed2017-08-17 14:10:50 -0700405// Adds a StreamParams for each SenderOptions in |sender_options| to
406// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000407// |current_params| - All currently known StreamParams of any media type.
408template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700409static bool AddStreamParams(
410 const std::vector<SenderOptions>& sender_options,
411 const std::string& rtcp_cname,
412 StreamParamsVec* current_streams,
413 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700414 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700415 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700416 return true;
417 }
418
Noah Richards2e7a0982015-05-18 14:02:54 -0700419 const bool include_rtx_streams =
420 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421
brandtr03d5fb12016-11-22 03:37:59 -0800422 const bool include_flexfec_stream =
423 ContainsFlexfecCodec(content_description->codecs());
424
zhihuang1c378ed2017-08-17 14:10:50 -0700425 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 // groupid is empty for StreamParams generated using
427 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700428 StreamParams* param =
429 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000430 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700431 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200432 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700433 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700435 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000436 // Add the generated ssrc.
437 for (size_t i = 0; i < ssrcs.size(); ++i) {
438 stream_param.ssrcs.push_back(ssrcs[i]);
439 }
zhihuang1c378ed2017-08-17 14:10:50 -0700440 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000441 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
442 stream_param.ssrc_groups.push_back(group);
443 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700444 // Generate extra ssrcs for include_rtx_streams case.
445 if (include_rtx_streams) {
446 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200447 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700448 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
449 &rtx_ssrcs);
450 for (size_t i = 0; i < ssrcs.size(); ++i) {
451 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
452 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 }
brandtr03d5fb12016-11-22 03:37:59 -0800454 // Generate extra ssrc for include_flexfec_stream case.
455 if (include_flexfec_stream) {
456 // TODO(brandtr): Update when we support multistream protection.
457 if (ssrcs.size() == 1) {
458 std::vector<uint32_t> flexfec_ssrcs;
459 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
460 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
brandtr03d5fb12016-11-22 03:37:59 -0800461 } else if (!ssrcs.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100462 RTC_LOG(LS_WARNING)
brandtr03d5fb12016-11-22 03:37:59 -0800463 << "Our FlexFEC implementation only supports protecting "
Jonas Olsson45cc8902018-02-13 10:37:07 +0100464 "a single media streams. This session has multiple "
465 "media streams however, so no FlexFEC SSRC will be generated.";
brandtr03d5fb12016-11-22 03:37:59 -0800466 }
467 }
zhihuang1c378ed2017-08-17 14:10:50 -0700468 stream_param.cname = rtcp_cname;
Seth Hampson845e8782018-03-02 11:34:10 -0800469 stream_param.set_stream_ids(sender.stream_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 content_description->AddStream(stream_param);
471
472 // Store the new StreamParams in current_streams.
473 // This is necessary so that we can use the CNAME for other media types.
474 current_streams->push_back(stream_param);
475 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700476 // Use existing generated SSRCs/groups, but update the sync_label if
477 // necessary. This may be needed if a MediaStreamTrack was moved from one
478 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800479 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000480 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 }
482 }
483 return true;
484}
485
486// Updates the transport infos of the |sdesc| according to the given
487// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800488// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
489// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
491 SessionDescription* sdesc) {
492 // The bundle should not be empty.
493 if (!sdesc || !bundle_group.FirstContentName()) {
494 return false;
495 }
496
497 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700498 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 const TransportInfo* selected_transport_info =
500 sdesc->GetTransportInfoByName(selected_content_name);
501 if (!selected_transport_info) {
502 return false;
503 }
504
505 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700506 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700508 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800510 ConnectionRole selected_connection_role =
511 selected_transport_info->description.connection_role;
Steve Anton3a66edf2018-09-10 12:57:37 -0700512 for (TransportInfo& transport_info : sdesc->transport_infos()) {
513 if (bundle_group.HasContentName(transport_info.content_name) &&
514 transport_info.content_name != selected_content_name) {
515 transport_info.description.ice_ufrag = selected_ufrag;
516 transport_info.description.ice_pwd = selected_pwd;
517 transport_info.description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 }
519 }
520 return true;
521}
522
523// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
524// sets it to |cryptos|.
525static bool GetCryptosByName(const SessionDescription* sdesc,
526 const std::string& content_name,
527 CryptoParamsVec* cryptos) {
528 if (!sdesc || !cryptos) {
529 return false;
530 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800532 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 return false;
534 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800535 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 return true;
537}
538
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
540// which are not available in |filter|.
541static void PruneCryptos(const CryptoParamsVec& filter,
542 CryptoParamsVec* target_cryptos) {
543 if (!target_cryptos) {
544 return;
545 }
tzik21995802018-04-26 17:38:28 +0900546
547 target_cryptos->erase(
548 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
549 // Returns true if the |crypto|'s cipher_suite is not
550 // found in |filter|.
551 [&filter](const CryptoParams& crypto) {
552 for (const CryptoParams& entry : filter) {
553 if (entry.cipher_suite == crypto.cipher_suite)
554 return false;
555 }
556 return true;
557 }),
558 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559}
560
Steve Antonfa2260d2017-12-28 16:38:23 -0800561bool IsRtpProtocol(const std::string& protocol) {
deadbeefb5cb19b2015-11-23 16:39:12 -0800562 return protocol.empty() ||
563 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
564}
565
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566static bool IsRtpContent(SessionDescription* sdesc,
567 const std::string& content_name) {
568 bool is_rtp = false;
569 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800570 if (content && content->media_description()) {
571 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 }
573 return is_rtp;
574}
575
576// Updates the crypto parameters of the |sdesc| according to the given
577// |bundle_group|. The crypto parameters of all the contents within the
578// |bundle_group| should be updated to use the common subset of the
579// available cryptos.
580static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
581 SessionDescription* sdesc) {
582 // The bundle should not be empty.
583 if (!sdesc || !bundle_group.FirstContentName()) {
584 return false;
585 }
586
wu@webrtc.org78187522013-10-07 23:32:02 +0000587 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 // Get the common cryptos.
589 const ContentNames& content_names = bundle_group.content_names();
590 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700591 bool first = true;
592 for (const std::string& content_name : content_names) {
593 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 continue;
595 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000596 // The common cryptos are needed if any of the content does not have DTLS
597 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700598 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000599 common_cryptos_needed = true;
600 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700601 if (first) {
602 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700604 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 return false;
606 }
607 if (common_cryptos.empty()) {
608 // If there's no crypto params, we should just return.
609 return true;
610 }
611 } else {
612 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700613 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 return false;
615 }
616 PruneCryptos(cryptos, &common_cryptos);
617 }
618 }
619
wu@webrtc.org78187522013-10-07 23:32:02 +0000620 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 return false;
622 }
623
624 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700625 for (const std::string& content_name : content_names) {
626 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 continue;
628 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700629 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 if (!media_desc) {
633 return false;
634 }
635 media_desc->set_cryptos(common_cryptos);
636 }
637 }
638 return true;
639}
640
641template <class C>
642static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800643 for (const auto& codec : codecs) {
644 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 return true;
646 }
647 }
648 return false;
649}
650
651template <class C>
652static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800653 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654}
655
brandtr03d5fb12016-11-22 03:37:59 -0800656template <class C>
657static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
658 for (const auto& codec : codecs) {
659 if (IsFlexfecCodec(codec)) {
660 return true;
661 }
662 }
663 return false;
664}
665
666template <class C>
667static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800668 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800669}
670
zhihuang1c378ed2017-08-17 14:10:50 -0700671// Create a media content to be offered for the given |sender_options|,
672// according to the given options.rtcp_mux, session_options.is_muc, codecs,
673// secure_transport, crypto, and current_streams. If we don't currently have
674// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
675// created (according to crypto_suites). The created content is added to the
676// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677template <class C>
678static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700679 const std::vector<SenderOptions>& sender_options,
680 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000682 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 const CryptoParamsVec* current_cryptos,
684 const std::vector<std::string>& crypto_suites,
685 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 StreamParamsVec* current_streams,
687 MediaContentDescriptionImpl<C>* offer) {
688 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689
zhihuang1c378ed2017-08-17 14:10:50 -0700690 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700691 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
692 offer->set_rtcp_reduced_size(true);
693 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 offer->set_rtp_header_extensions(rtp_extensions);
695
zhihuang1c378ed2017-08-17 14:10:50 -0700696 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
697 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 return false;
699 }
700
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 if (secure_policy != SEC_DISABLED) {
702 if (current_cryptos) {
703 AddMediaCryptos(*current_cryptos, offer);
704 }
705 if (offer->cryptos().empty()) {
706 if (!CreateMediaCryptos(crypto_suites, offer)) {
707 return false;
708 }
709 }
710 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711
deadbeef7af91dd2016-12-13 11:29:11 -0800712 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713 return false;
714 }
715 return true;
716}
717
718template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000719static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800720 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000721 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800722 const int codec2_id) {
723 const C* codec1 = FindCodecById(codecs1, codec1_id);
724 const C* codec2 = FindCodecById(codecs2, codec2_id);
725 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000726}
727
728template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729static void NegotiateCodecs(const std::vector<C>& local_codecs,
730 const std::vector<C>& offered_codecs,
731 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800732 for (const C& ours : local_codecs) {
733 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700734 // Note that we intentionally only find one matching codec for each of our
735 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800736 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
737 C negotiated = ours;
738 negotiated.IntersectFeedbackParams(theirs);
739 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800740 const auto apt_it =
741 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800742 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800743 RTC_DCHECK(apt_it != theirs.params.end());
744 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 }
magjedf823ede2016-11-12 09:53:04 -0800746 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
747 webrtc::H264::GenerateProfileLevelIdForAnswer(
748 ours.params, theirs.params, &negotiated.params);
749 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800750 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700751 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800752 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 }
754 }
deadbeef67cf2c12016-04-13 10:07:16 -0700755 // RFC3264: Although the answerer MAY list the formats in their desired
756 // order of preference, it is RECOMMENDED that unless there is a
757 // specific reason, the answerer list formats in the same relative order
758 // they were present in the offer.
759 std::unordered_map<int, int> payload_type_preferences;
760 int preference = static_cast<int>(offered_codecs.size() + 1);
761 for (const C& codec : offered_codecs) {
762 payload_type_preferences[codec.id] = preference--;
763 }
764 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
765 [&payload_type_preferences](const C& a, const C& b) {
766 return payload_type_preferences[a.id] >
767 payload_type_preferences[b.id];
768 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769}
770
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800771// Finds a codec in |codecs2| that matches |codec_to_match|, which is
772// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
773// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800775static bool FindMatchingCodec(const std::vector<C>& codecs1,
776 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 const C& codec_to_match,
778 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700779 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
780 // codecs' associated codecs correctly. If not, that's a programming error.
781 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
782 [&codec_to_match](const C& codec) {
783 return &codec == &codec_to_match;
784 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800785 for (const C& potential_match : codecs2) {
786 if (potential_match.Matches(codec_to_match)) {
787 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800788 int apt_value_1 = 0;
789 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800790 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
791 &apt_value_1) ||
792 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
793 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100794 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800795 continue;
796 }
797 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
798 apt_value_2)) {
799 continue;
800 }
801 }
802 if (found_codec) {
803 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 }
805 return true;
806 }
807 }
808 return false;
809}
810
zhihuang1c378ed2017-08-17 14:10:50 -0700811// Find the codec in |codec_list| that |rtx_codec| is associated with.
812template <class C>
813static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
814 const C& rtx_codec) {
815 std::string associated_pt_str;
816 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
817 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100818 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
819 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700820 return nullptr;
821 }
822
823 int associated_pt;
824 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100825 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
826 << " of RTX codec " << rtx_codec.name
827 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700828 return nullptr;
829 }
830
831 // Find the associated reference codec for the reference RTX codec.
832 const C* associated_codec = FindCodecById(codec_list, associated_pt);
833 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100834 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
835 << associated_pt << " for RTX codec " << rtx_codec.name
836 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700837 }
838 return associated_codec;
839}
840
841// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842// already exist in |offered_codecs| and ensure the payload types don't
843// collide.
844template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700845static void MergeCodecs(const std::vector<C>& reference_codecs,
846 std::vector<C>* offered_codecs,
847 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800849 for (const C& reference_codec : reference_codecs) {
850 if (!IsRtxCodec(reference_codec) &&
851 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
852 reference_codec, nullptr)) {
853 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 used_pltypes->FindAndSetIdUsed(&codec);
855 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 }
857 }
858
859 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800860 for (const C& reference_codec : reference_codecs) {
861 if (IsRtxCodec(reference_codec) &&
862 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
863 reference_codec, nullptr)) {
864 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700865 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700866 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700867 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700868 continue;
869 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800870 // Find a codec in the offered list that matches the reference codec.
871 // Its payload type may be different than the reference codec.
872 C matching_codec;
873 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800874 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100875 RTC_LOG(LS_WARNING)
876 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800877 continue;
878 }
879
880 rtx_codec.params[kCodecParamAssociatedPayloadType] =
881 rtc::ToString(matching_codec.id);
882 used_pltypes->FindAndSetIdUsed(&rtx_codec);
883 offered_codecs->push_back(rtx_codec);
884 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885 }
886}
887
zhihuang1c378ed2017-08-17 14:10:50 -0700888static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
889 const webrtc::RtpExtension& ext_to_match,
890 webrtc::RtpExtension* found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700891 auto it =
892 std::find_if(extensions.begin(), extensions.end(),
893 [&ext_to_match](const webrtc::RtpExtension& extension) {
894 // We assume that all URIs are given in a canonical
895 // format.
896 return extension.uri == ext_to_match.uri &&
897 extension.encrypt == ext_to_match.encrypt;
898 });
899 if (it == extensions.end()) {
900 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700901 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700902 if (found_extension) {
903 *found_extension = *it;
904 }
905 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700906}
907
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700909 const webrtc::RtpExtension& ext_to_match,
910 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700911 // We assume that all URIs are given in a canonical format.
912 const webrtc::RtpExtension* found =
913 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
914 ext_to_match.uri);
915 if (!found) {
916 return false;
917 }
918 if (found_extension) {
919 *found_extension = *found;
920 }
921 return true;
922}
923
924static bool FindByUriWithEncryptionPreference(
925 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200926 const webrtc::RtpExtension& ext_to_match,
927 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700928 webrtc::RtpExtension* found_extension) {
929 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700930 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700932 if (extension.uri == ext_to_match.uri) {
933 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700934 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700935 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700936 }
937 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700939 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 }
941 }
jbauch5869f502017-06-29 12:31:36 -0700942 if (unencrypted_extension) {
943 if (found_extension) {
944 *found_extension = *unencrypted_extension;
945 }
946 return true;
947 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 return false;
949}
950
zhihuang1c378ed2017-08-17 14:10:50 -0700951// Adds all extensions from |reference_extensions| to |offered_extensions| that
952// don't already exist in |offered_extensions| and ensure the IDs don't
953// collide. If an extension is added, it's also added to |regular_extensions| or
954// |encrypted_extensions|, and if the extension is in |regular_extensions| or
955// |encrypted_extensions|, its ID is marked as used in |used_ids|.
956// |offered_extensions| is for either audio or video while |regular_extensions|
957// and |encrypted_extensions| are used for both audio and video. There could be
958// overlap between audio extensions and video extensions.
959static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
960 RtpHeaderExtensions* offered_extensions,
961 RtpHeaderExtensions* regular_extensions,
962 RtpHeaderExtensions* encrypted_extensions,
963 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -0700964 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -0700965 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
966 nullptr)) {
olka3c747662017-08-17 06:50:32 -0700967 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -0700968 if (reference_extension.encrypt) {
969 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
970 &existing)) {
971 offered_extensions->push_back(existing);
972 } else {
973 used_ids->FindAndSetIdUsed(&reference_extension);
974 encrypted_extensions->push_back(reference_extension);
975 offered_extensions->push_back(reference_extension);
976 }
olka3c747662017-08-17 06:50:32 -0700977 } else {
zhihuang1c378ed2017-08-17 14:10:50 -0700978 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
979 &existing)) {
980 offered_extensions->push_back(existing);
981 } else {
982 used_ids->FindAndSetIdUsed(&reference_extension);
983 regular_extensions->push_back(reference_extension);
984 offered_extensions->push_back(reference_extension);
985 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000986 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 }
988 }
989}
990
jbauch5869f502017-06-29 12:31:36 -0700991static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
992 RtpHeaderExtensions* all_extensions,
993 UsedRtpHeaderExtensionIds* used_ids) {
994 RtpHeaderExtensions encrypted_extensions;
995 for (const webrtc::RtpExtension& extension : *extensions) {
996 webrtc::RtpExtension existing;
997 // Don't add encrypted extensions again that were already included in a
998 // previous offer or regular extensions that are also included as encrypted
999 // extensions.
1000 if (extension.encrypt ||
1001 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1002 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001003 &existing) &&
1004 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001005 continue;
1006 }
1007
1008 if (FindByUri(*all_extensions, extension, &existing)) {
1009 encrypted_extensions.push_back(existing);
1010 } else {
1011 webrtc::RtpExtension encrypted(extension);
1012 encrypted.encrypt = true;
1013 used_ids->FindAndSetIdUsed(&encrypted);
1014 all_extensions->push_back(encrypted);
1015 encrypted_extensions.push_back(encrypted);
1016 }
1017 }
1018 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001019 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001020}
1021
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022static void NegotiateRtpHeaderExtensions(
1023 const RtpHeaderExtensions& local_extensions,
1024 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001025 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026 RtpHeaderExtensions* negotiated_extenstions) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001027 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001028 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001029 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001030 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001031 &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 // We respond with their RTP header extension id.
1033 negotiated_extenstions->push_back(theirs);
1034 }
1035 }
1036}
1037
1038static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001039 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1040 [](const AudioCodec& codec) {
1041 return STR_CASE_CMP(
1042 codec.name.c_str(),
1043 kComfortNoiseCodecName) == 0;
1044 }),
1045 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046}
1047
zhihuang1c378ed2017-08-17 14:10:50 -07001048// Create a media content to be answered for the given |sender_options|
1049// according to the given session_options.rtcp_mux, session_options.streams,
1050// codecs, crypto, and current_streams. If we don't currently have crypto (in
1051// current_cryptos) and it is enabled (in secure_policy), crypto is created
1052// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1053// negotiated with the offer. If the negotiation fails, this method returns
1054// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055template <class C>
1056static bool CreateMediaContentAnswer(
1057 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001058 const MediaDescriptionOptions& media_description_options,
1059 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001061 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062 const CryptoParamsVec* current_cryptos,
1063 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001064 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001066 bool bundle_enabled,
1067 MediaContentDescriptionImpl<C>* answer) {
1068 std::vector<C> negotiated_codecs;
1069 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1070 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001071 answer->set_protocol(offer->protocol());
Johannes Kron0854eb62018-10-10 22:33:20 +02001072
1073 answer->set_mixed_one_two_byte_header_extensions_supported(
1074 offer->mixed_one_two_byte_header_extensions_supported());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001076 NegotiateRtpHeaderExtensions(
1077 local_rtp_extenstions, offer->rtp_header_extensions(),
1078 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001079 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1080
zhihuang1c378ed2017-08-17 14:10:50 -07001081 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001082 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1083 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1084 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001085
1086 if (sdes_policy != SEC_DISABLED) {
1087 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001088 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1089 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 if (current_cryptos) {
1091 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1092 }
1093 answer->AddCrypto(crypto);
1094 }
1095 }
1096
deadbeef7af91dd2016-12-13 11:29:11 -08001097 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 return false;
1099 }
1100
zhihuang1c378ed2017-08-17 14:10:50 -07001101 if (!AddStreamParams(media_description_options.sender_options,
1102 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103 return false; // Something went seriously wrong.
1104 }
1105
Steve Anton4e70a722017-11-28 14:57:10 -08001106 answer->set_direction(NegotiateRtpTransceiverDirection(
1107 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108 return true;
1109}
1110
1111static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001112 const std::string& protocol,
1113 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001114 // Since not all applications serialize and deserialize the media protocol,
1115 // we will have to accept |protocol| to be empty.
1116 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001117 return true;
1118 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001119
zhihuangcf5b37c2016-05-05 11:44:35 -07001120 if (type == MEDIA_TYPE_DATA) {
1121 // Check for SCTP, but also for RTP for RTP-based data channels.
1122 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1123 if (secure_transport) {
1124 // Most likely scenarios first.
1125 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1126 IsPlainRtp(protocol);
1127 } else {
1128 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1129 }
1130 }
1131
1132 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1133 // JSEP specifies.
1134 if (secure_transport) {
1135 // Most likely scenarios first.
1136 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1137 } else {
1138 return IsPlainRtp(protocol);
1139 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140}
1141
1142static void SetMediaProtocol(bool secure_transport,
1143 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001144 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001146 else if (secure_transport)
1147 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 else
1149 desc->set_protocol(kMediaProtocolAvpf);
1150}
1151
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001152// Gets the TransportInfo of the given |content_name| from the
1153// |current_description|. If doesn't exist, returns a new one.
1154static const TransportDescription* GetTransportDescription(
1155 const std::string& content_name,
1156 const SessionDescription* current_description) {
1157 const TransportDescription* desc = NULL;
1158 if (current_description) {
1159 const TransportInfo* info =
1160 current_description->GetTransportInfoByName(content_name);
1161 if (info) {
1162 desc = &info->description;
1163 }
1164 }
1165 return desc;
1166}
1167
1168// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001169static bool IsDtlsActive(const ContentInfo* content,
1170 const SessionDescription* current_description) {
1171 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001172 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001173 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001174
zhihuang1c378ed2017-08-17 14:10:50 -07001175 size_t msection_index = content - &current_description->contents()[0];
1176
1177 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001178 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001179 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001180
zhihuang1c378ed2017-08-17 14:10:50 -07001181 return current_description->transport_infos()[msection_index]
1182 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001183}
1184
Steve Anton8ffb9c32017-08-31 15:45:38 -07001185void MediaDescriptionOptions::AddAudioSender(
1186 const std::string& track_id,
1187 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001188 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001189 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001190}
1191
Steve Anton8ffb9c32017-08-31 15:45:38 -07001192void MediaDescriptionOptions::AddVideoSender(
1193 const std::string& track_id,
1194 const std::vector<std::string>& stream_ids,
1195 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001196 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001197 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001198}
1199
zhihuang1c378ed2017-08-17 14:10:50 -07001200void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1201 const std::string& stream_id) {
1202 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001203 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1204 // than one stream?
1205 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206}
1207
Steve Anton8ffb9c32017-08-31 15:45:38 -07001208void MediaDescriptionOptions::AddSenderInternal(
1209 const std::string& track_id,
1210 const std::vector<std::string>& stream_ids,
1211 int num_sim_layers) {
1212 // TODO(steveanton): Support any number of stream ids.
1213 RTC_CHECK(stream_ids.size() == 1U);
1214 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215}
1216
zhihuang1c378ed2017-08-17 14:10:50 -07001217bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1218 return std::find_if(media_description_options.begin(),
1219 media_description_options.end(),
1220 [type](const MediaDescriptionOptions& t) {
1221 return t.type == type;
1222 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001223}
1224
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1226 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001227 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228
1229MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1230 ChannelManager* channel_manager,
1231 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001232 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001233 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1234 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001236 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1238 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001239 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001240}
1241
ossudedfd282016-06-14 07:12:39 -07001242const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1243 const {
ossu075af922016-06-14 03:29:38 -07001244 return audio_sendrecv_codecs_;
1245}
1246
1247const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1248 return audio_send_codecs_;
1249}
1250
1251const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1252 return audio_recv_codecs_;
1253}
1254
1255void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001256 const AudioCodecs& send_codecs,
1257 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001258 audio_send_codecs_ = send_codecs;
1259 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001260 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261}
1262
1263SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001264 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001265 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001266 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001268 IceCredentialsIterator ice_credentials(
1269 session_options.pooled_ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 StreamParamsVec current_streams;
1271 GetCurrentStreamParams(current_description, &current_streams);
1272
zhihuang1c378ed2017-08-17 14:10:50 -07001273 AudioCodecs offer_audio_codecs;
1274 VideoCodecs offer_video_codecs;
1275 DataCodecs offer_data_codecs;
1276 GetCodecsForOffer(current_description, &offer_audio_codecs,
1277 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001278
zhihuang1c378ed2017-08-17 14:10:50 -07001279 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001281 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 }
zhihuang1c378ed2017-08-17 14:10:50 -07001283 FilterDataCodecs(&offer_data_codecs,
1284 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285
1286 RtpHeaderExtensions audio_rtp_extensions;
1287 RtpHeaderExtensions video_rtp_extensions;
Steve Anton1b8773d2018-04-06 11:13:34 -07001288 GetRtpHdrExtsToOffer(session_options, current_description,
1289 &audio_rtp_extensions, &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290
zhihuang1c378ed2017-08-17 14:10:50 -07001291 // Must have options for each existing section.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001292 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001293 RTC_DCHECK(current_description->contents().size() <=
1294 session_options.media_description_options.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001296
zhihuang1c378ed2017-08-17 14:10:50 -07001297 // Iterate through the media description options, matching with existing media
1298 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001299 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001300 for (const MediaDescriptionOptions& media_description_options :
1301 session_options.media_description_options) {
1302 const ContentInfo* current_content = nullptr;
1303 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001304 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001305 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001306 // Media type must match unless this media section is being recycled.
1307 RTC_DCHECK(current_content->rejected ||
1308 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001309 media_description_options.type));
1310 }
1311 switch (media_description_options.type) {
1312 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001313 if (!AddAudioContentForOffer(
1314 media_description_options, session_options, current_content,
1315 current_description, audio_rtp_extensions, offer_audio_codecs,
1316 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001317 return nullptr;
1318 }
1319 break;
1320 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001321 if (!AddVideoContentForOffer(
1322 media_description_options, session_options, current_content,
1323 current_description, video_rtp_extensions, offer_video_codecs,
1324 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001325 return nullptr;
1326 }
1327 break;
1328 case MEDIA_TYPE_DATA:
1329 if (!AddDataContentForOffer(media_description_options, session_options,
1330 current_content, current_description,
1331 offer_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001332 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001333 return nullptr;
1334 }
1335 break;
1336 default:
1337 RTC_NOTREACHED();
1338 }
1339 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340 }
1341
1342 // Bundle the contents together, if we've been asked to do so, and update any
1343 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001344 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001345 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001346 for (const ContentInfo& content : offer->contents()) {
1347 // TODO(deadbeef): There are conditions that make bundling two media
1348 // descriptions together illegal. For example, they use the same payload
1349 // type to represent different codecs, or same IDs for different header
1350 // extensions. We need to detect this and not try to bundle those media
1351 // descriptions together.
1352 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353 }
1354 offer->AddGroup(offer_bundle);
1355 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001356 RTC_LOG(LS_ERROR)
1357 << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001358 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359 }
1360 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001361 RTC_LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001362 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001363 }
1364 }
Steve Antone831b8c2018-02-01 12:22:16 -08001365
1366 // The following determines how to signal MSIDs to ensure compatibility with
1367 // older endpoints (in particular, older Plan B endpoints).
1368 if (session_options.is_unified_plan) {
1369 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1370 // Plan answerers will look at a=msid and Plan B answerers will look at the
1371 // a=ssrc MSID line.
1372 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1373 cricket::kMsidSignalingSsrcAttribute);
1374 } else {
1375 // Plan B always signals MSID using a=ssrc lines.
1376 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1377 }
1378
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001379 return offer.release();
1380}
1381
1382SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001383 const SessionDescription* offer,
1384 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001385 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001386 if (!offer) {
1387 return nullptr;
1388 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001389
1390 IceCredentialsIterator ice_credentials(
1391 session_options.pooled_ice_credentials);
1392
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001393 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001394 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1395 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001396 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397
1398 StreamParamsVec current_streams;
1399 GetCurrentStreamParams(current_description, &current_streams);
1400
deadbeefb7892532017-02-22 19:35:18 -08001401 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1402 // group in the answer with the appropriate content names.
1403 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1404 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1405 // Transport info shared by the bundle group.
1406 std::unique_ptr<TransportInfo> bundle_transport;
1407
Johannes Kron0854eb62018-10-10 22:33:20 +02001408 answer->set_mixed_one_two_byte_header_extensions_supported(
1409 offer->mixed_one_two_byte_header_extensions_supported());
1410
zhihuang1c378ed2017-08-17 14:10:50 -07001411 // Get list of all possible codecs that respects existing payload type
1412 // mappings and uses a single payload type space.
1413 //
1414 // Note that these lists may be further filtered for each m= section; this
1415 // step is done just to establish the payload type mappings shared by all
1416 // sections.
1417 AudioCodecs answer_audio_codecs;
1418 VideoCodecs answer_video_codecs;
1419 DataCodecs answer_data_codecs;
1420 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
1421 &answer_video_codecs, &answer_data_codecs);
1422
1423 if (!session_options.vad_enabled) {
1424 // If application doesn't want CN codecs in answer.
1425 StripCNCodecs(&answer_audio_codecs);
1426 }
1427 FilterDataCodecs(&answer_data_codecs,
1428 session_options.data_channel_type == DCT_SCTP);
1429
1430 // Must have options for exactly as many sections as in the offer.
1431 RTC_DCHECK(offer->contents().size() ==
1432 session_options.media_description_options.size());
1433 // Iterate through the media description options, matching with existing
1434 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001435 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001436 for (const MediaDescriptionOptions& media_description_options :
1437 session_options.media_description_options) {
1438 const ContentInfo* offer_content = &offer->contents()[msection_index];
1439 // Media types and MIDs must match between the remote offer and the
1440 // MediaDescriptionOptions.
1441 RTC_DCHECK(
1442 IsMediaContentOfType(offer_content, media_description_options.type));
1443 RTC_DCHECK(media_description_options.mid == offer_content->name);
1444 const ContentInfo* current_content = nullptr;
1445 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001446 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001447 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001448 }
zhihuang1c378ed2017-08-17 14:10:50 -07001449 switch (media_description_options.type) {
1450 case MEDIA_TYPE_AUDIO:
1451 if (!AddAudioContentForAnswer(
1452 media_description_options, session_options, offer_content,
1453 offer, current_content, current_description,
1454 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001455 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001456 return nullptr;
1457 }
1458 break;
1459 case MEDIA_TYPE_VIDEO:
1460 if (!AddVideoContentForAnswer(
1461 media_description_options, session_options, offer_content,
1462 offer, current_content, current_description,
1463 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001464 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001465 return nullptr;
1466 }
1467 break;
1468 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001469 if (!AddDataContentForAnswer(
1470 media_description_options, session_options, offer_content,
1471 offer, current_content, current_description,
1472 bundle_transport.get(), answer_data_codecs, &current_streams,
1473 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001474 return nullptr;
1475 }
1476 break;
1477 default:
1478 RTC_NOTREACHED();
1479 }
1480 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001481 // See if we can add the newly generated m= section to the BUNDLE group in
1482 // the answer.
1483 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001484 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001485 offer_bundle->HasContentName(added.name)) {
1486 answer_bundle.AddContentName(added.name);
1487 bundle_transport.reset(
1488 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490 }
1491
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001492 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1493 // it's empty. RFC5888 says:
1494 //
1495 // A SIP entity that receives an offer that contains an "a=group" line
1496 // with semantics that are understood MUST return an answer that
1497 // contains an "a=group" line with the same semantics.
1498 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001499 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001500 }
deadbeefb7892532017-02-22 19:35:18 -08001501
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001502 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001503 // Share the same ICE credentials and crypto params across all contents,
1504 // as BUNDLE requires.
1505 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001506 RTC_LOG(LS_ERROR)
1507 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001508 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001509 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001510
deadbeefb7892532017-02-22 19:35:18 -08001511 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001512 RTC_LOG(LS_ERROR)
1513 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001514 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001515 }
1516 }
1517
Steve Antone831b8c2018-02-01 12:22:16 -08001518 // The following determines how to signal MSIDs to ensure compatibility with
1519 // older endpoints (in particular, older Plan B endpoints).
1520 if (session_options.is_unified_plan) {
1521 // Unified Plan needs to look at what the offer included to find the most
1522 // compatible answer.
1523 if (offer->msid_signaling() == 0) {
1524 // We end up here in one of three cases:
1525 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1526 // matter what we pick here.
1527 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1528 // it also doesn't matter what we pick here.
1529 // 3. Media that's either sendonly or inactive from the remote endpoint.
1530 // We don't have any information to say whether the endpoint is Plan B
1531 // or Unified Plan, so be conservative and send both.
1532 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1533 cricket::kMsidSignalingSsrcAttribute);
1534 } else if (offer->msid_signaling() ==
1535 (cricket::kMsidSignalingMediaSection |
1536 cricket::kMsidSignalingSsrcAttribute)) {
1537 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1538 // probably talking to a Unified Plan endpoint so respond with just
1539 // a=msid.
1540 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1541 } else {
1542 // Otherwise, it's clear which method the offerer is using so repeat that
1543 // back to them.
1544 answer->set_msid_signaling(offer->msid_signaling());
1545 }
1546 } else {
1547 // Plan B always signals MSID using a=ssrc lines.
1548 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1549 }
1550
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001551 return answer.release();
1552}
1553
ossu075af922016-06-14 03:29:38 -07001554const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1555 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001556 switch (direction) {
1557 // If stream is inactive - generate list as if sendrecv.
1558 case RtpTransceiverDirection::kSendRecv:
1559 case RtpTransceiverDirection::kInactive:
1560 return audio_sendrecv_codecs_;
1561 case RtpTransceiverDirection::kSendOnly:
1562 return audio_send_codecs_;
1563 case RtpTransceiverDirection::kRecvOnly:
1564 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001565 }
Steve Anton1d03a752017-11-27 14:30:09 -08001566 RTC_NOTREACHED();
1567 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001568}
1569
1570const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1571 const RtpTransceiverDirection& offer,
1572 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001573 switch (answer) {
1574 // For inactive and sendrecv answers, generate lists as if we were to accept
1575 // the offer's direction. See RFC 3264 Section 6.1.
1576 case RtpTransceiverDirection::kSendRecv:
1577 case RtpTransceiverDirection::kInactive:
1578 return GetAudioCodecsForOffer(
1579 webrtc::RtpTransceiverDirectionReversed(offer));
1580 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001581 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001582 case RtpTransceiverDirection::kRecvOnly:
1583 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001584 }
Steve Anton1d03a752017-11-27 14:30:09 -08001585 RTC_NOTREACHED();
1586 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001587}
1588
zhihuang1c378ed2017-08-17 14:10:50 -07001589void MergeCodecsFromDescription(const SessionDescription* description,
1590 AudioCodecs* audio_codecs,
1591 VideoCodecs* video_codecs,
1592 DataCodecs* data_codecs,
1593 UsedPayloadTypes* used_pltypes) {
1594 RTC_DCHECK(description);
1595 for (const ContentInfo& content : description->contents()) {
1596 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1597 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001598 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001599 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1600 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1601 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001602 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001603 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1604 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1605 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001606 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001607 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1608 }
1609 }
1610}
1611
1612// Getting codecs for an offer involves these steps:
1613//
1614// 1. Construct payload type -> codec mappings for current description.
1615// 2. Add any reference codecs that weren't already present
1616// 3. For each individual media description (m= section), filter codecs based
1617// on the directional attribute (happens in another method).
1618void MediaSessionDescriptionFactory::GetCodecsForOffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001619 const SessionDescription* current_description,
1620 AudioCodecs* audio_codecs,
1621 VideoCodecs* video_codecs,
1622 DataCodecs* data_codecs) const {
1623 UsedPayloadTypes used_pltypes;
1624 audio_codecs->clear();
1625 video_codecs->clear();
1626 data_codecs->clear();
1627
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001629 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1630 // new media type is added.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001632 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1633 data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 }
1635
1636 // Add our codecs that are not in |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001637 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1638 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1639 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1640}
1641
1642// Getting codecs for an answer involves these steps:
1643//
1644// 1. Construct payload type -> codec mappings for current description.
1645// 2. Add any codecs from the offer that weren't already present.
1646// 3. Add any remaining codecs that weren't already present.
1647// 4. For each individual media description (m= section), filter codecs based
1648// on the directional attribute (happens in another method).
1649void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1650 const SessionDescription* current_description,
1651 const SessionDescription* remote_offer,
1652 AudioCodecs* audio_codecs,
1653 VideoCodecs* video_codecs,
1654 DataCodecs* data_codecs) const {
1655 UsedPayloadTypes used_pltypes;
1656 audio_codecs->clear();
1657 video_codecs->clear();
1658 data_codecs->clear();
1659
1660 // First - get all codecs from the current description if the media type
1661 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1662 // new media type is added.
1663 if (current_description) {
1664 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1665 data_codecs, &used_pltypes);
1666 }
1667
1668 // Second - filter out codecs that we don't support at all and should ignore.
1669 AudioCodecs filtered_offered_audio_codecs;
1670 VideoCodecs filtered_offered_video_codecs;
1671 DataCodecs filtered_offered_data_codecs;
1672 for (const ContentInfo& content : remote_offer->contents()) {
1673 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1674 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001675 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001676 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1677 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1678 filtered_offered_audio_codecs,
1679 offered_audio_codec, nullptr) &&
1680 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1681 offered_audio_codec, nullptr)) {
1682 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1683 }
1684 }
1685 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1686 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001687 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001688 for (const VideoCodec& offered_video_codec : video->codecs()) {
1689 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1690 filtered_offered_video_codecs,
1691 offered_video_codec, nullptr) &&
1692 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1693 offered_video_codec, nullptr)) {
1694 filtered_offered_video_codecs.push_back(offered_video_codec);
1695 }
1696 }
1697 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1698 const DataContentDescription* data =
Steve Antonb1c1de12017-12-21 15:14:30 -08001699 content.media_description()->as_data();
zhihuang1c378ed2017-08-17 14:10:50 -07001700 for (const DataCodec& offered_data_codec : data->codecs()) {
1701 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1702 filtered_offered_data_codecs,
1703 offered_data_codec, nullptr) &&
1704 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1705 offered_data_codec, nullptr)) {
1706 filtered_offered_data_codecs.push_back(offered_data_codec);
1707 }
1708 }
1709 }
1710 }
1711
1712 // Add codecs that are not in |current_description| but were in
1713 // |remote_offer|.
1714 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1715 &used_pltypes);
1716 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1717 &used_pltypes);
1718 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1719 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720}
1721
1722void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton1b8773d2018-04-06 11:13:34 -07001723 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001724 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001725 RtpHeaderExtensions* offer_audio_extensions,
1726 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001727 // All header extensions allocated from the same range to avoid potential
1728 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001729 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001730 RtpHeaderExtensions all_regular_extensions;
1731 RtpHeaderExtensions all_encrypted_extensions;
zhihuang1c378ed2017-08-17 14:10:50 -07001732 offer_audio_extensions->clear();
1733 offer_video_extensions->clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001734
1735 // First - get all extensions from the current description if the media type
1736 // is used.
1737 // Add them to |used_ids| so the local ids are not reused if a new media
1738 // type is added.
1739 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001740 for (const ContentInfo& content : current_description->contents()) {
1741 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1742 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001743 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001744 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1745 &all_regular_extensions, &all_encrypted_extensions,
1746 &used_ids);
1747 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1748 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001749 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001750 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1751 &all_regular_extensions, &all_encrypted_extensions,
1752 &used_ids);
1753 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001754 }
1755 }
1756
1757 // Add our default RTP header extensions that are not in
1758 // |current_description|.
Steve Anton1b8773d2018-04-06 11:13:34 -07001759 MergeRtpHdrExts(audio_rtp_header_extensions(session_options.is_unified_plan),
1760 offer_audio_extensions, &all_regular_extensions,
1761 &all_encrypted_extensions, &used_ids);
1762 MergeRtpHdrExts(video_rtp_header_extensions(session_options.is_unified_plan),
1763 offer_video_extensions, &all_regular_extensions,
1764 &all_encrypted_extensions, &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001765
jbauch5869f502017-06-29 12:31:36 -07001766 // TODO(jbauch): Support adding encrypted header extensions to existing
1767 // sessions.
1768 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001769 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1770 &all_encrypted_extensions, &used_ids);
1771 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1772 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001773 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774}
1775
1776bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001777 const std::string& content_name,
1778 const TransportOptions& transport_options,
1779 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001780 SessionDescription* offer_desc,
1781 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001782 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001783 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 const TransportDescription* current_tdesc =
1785 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001786 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001787 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1788 ice_credentials));
Yves Gerey665174f2018-06-19 15:03:05 +02001789 bool ret =
1790 (new_tdesc.get() != NULL &&
1791 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 if (!ret) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001793 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1794 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 }
1796 return ret;
1797}
1798
1799TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1800 const std::string& content_name,
1801 const SessionDescription* offer_desc,
1802 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001803 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001804 bool require_transport_attributes,
1805 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806 if (!transport_desc_factory_)
1807 return NULL;
1808 const TransportDescription* offer_tdesc =
1809 GetTransportDescription(content_name, offer_desc);
1810 const TransportDescription* current_tdesc =
1811 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001812 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1813 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001814 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815}
1816
1817bool MediaSessionDescriptionFactory::AddTransportAnswer(
1818 const std::string& content_name,
1819 const TransportDescription& transport_desc,
1820 SessionDescription* answer_desc) const {
Yves Gerey665174f2018-06-19 15:03:05 +02001821 if (!answer_desc->AddTransportInfo(
1822 TransportInfo(content_name, transport_desc))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001823 RTC_LOG(LS_ERROR) << "Failed to AddTransportAnswer, content name="
1824 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 return false;
1826 }
1827 return true;
1828}
1829
zhihuang1c378ed2017-08-17 14:10:50 -07001830// |audio_codecs| = set of all possible codecs that can be used, with correct
1831// payload type mappings
1832//
1833// |supported_audio_codecs| = set of codecs that are supported for the direction
1834// of this m= section
1835//
1836// acd->codecs() = set of previously negotiated codecs for this m= section
1837//
1838// The payload types should come from audio_codecs, but the order should come
1839// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1840// change existing codec priority, and that new codecs are added with the right
1841// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001842bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001843 const MediaDescriptionOptions& media_description_options,
1844 const MediaSessionOptions& session_options,
1845 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001846 const SessionDescription* current_description,
1847 const RtpHeaderExtensions& audio_rtp_extensions,
1848 const AudioCodecs& audio_codecs,
1849 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001850 SessionDescription* desc,
1851 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001852 // Filter audio_codecs (which includes all codecs, with correctly remapped
1853 // payload types) based on transceiver direction.
1854 const AudioCodecs& supported_audio_codecs =
1855 GetAudioCodecsForOffer(media_description_options.direction);
1856
1857 AudioCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08001858 // Add the codecs from current content if it exists and is not being recycled.
1859 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001860 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001861 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001862 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001863 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001864 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1865 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001866 filtered_codecs.push_back(codec);
1867 }
1868 }
1869 }
1870 // Add other supported audio codecs.
1871 AudioCodec found_codec;
1872 for (const AudioCodec& codec : supported_audio_codecs) {
1873 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1874 codec, &found_codec) &&
1875 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1876 codec, nullptr)) {
1877 // Use the |found_codec| from |audio_codecs| because it has the correctly
1878 // mapped payload type.
1879 filtered_codecs.push_back(found_codec);
1880 }
1881 }
deadbeef44f08192015-12-15 16:20:09 -08001882
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001883 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001884 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1885 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001886
kwiberg31022942016-03-11 14:18:21 -08001887 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001888 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001889 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1890 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001891 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001892 media_description_options.sender_options, session_options,
1893 filtered_codecs, sdes_policy, GetCryptos(current_content),
1894 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001895 return false;
1896 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001897
1898 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1899 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001900
Steve Anton4e70a722017-11-28 14:57:10 -08001901 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001902
Steve Anton5adfafd2017-12-20 16:34:00 -08001903 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001904 media_description_options.stopped, audio.release());
1905 if (!AddTransportOffer(media_description_options.mid,
1906 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001907 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001908 return false;
1909 }
1910
1911 return true;
1912}
1913
1914bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001915 const MediaDescriptionOptions& media_description_options,
1916 const MediaSessionOptions& session_options,
1917 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001918 const SessionDescription* current_description,
1919 const RtpHeaderExtensions& video_rtp_extensions,
1920 const VideoCodecs& video_codecs,
1921 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001922 SessionDescription* desc,
1923 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001924 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001925 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1926 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001927
kwiberg31022942016-03-11 14:18:21 -08001928 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001929 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001930 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1931 &crypto_suites);
1932
1933 VideoCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08001934 // Add the codecs from current content if it exists and is not being recycled.
1935 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001936 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07001937 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001938 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001939 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001940 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07001941 nullptr)) {
1942 filtered_codecs.push_back(codec);
1943 }
1944 }
1945 }
1946 // Add other supported video codecs.
1947 VideoCodec found_codec;
1948 for (const VideoCodec& codec : video_codecs_) {
1949 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1950 &found_codec) &&
1951 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1952 nullptr)) {
1953 // Use the |found_codec| from |video_codecs| because it has the correctly
1954 // mapped payload type.
1955 filtered_codecs.push_back(found_codec);
1956 }
1957 }
1958
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001959 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001960 media_description_options.sender_options, session_options,
1961 filtered_codecs, sdes_policy, GetCryptos(current_content),
1962 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001963 return false;
1964 }
1965
zhihuang1c378ed2017-08-17 14:10:50 -07001966 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001967
1968 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1969 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001970
Steve Anton4e70a722017-11-28 14:57:10 -08001971 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001972
Steve Anton5adfafd2017-12-20 16:34:00 -08001973 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07001974 media_description_options.stopped, video.release());
1975 if (!AddTransportOffer(media_description_options.mid,
1976 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001977 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001978 return false;
1979 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001980 return true;
1981}
1982
1983bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001984 const MediaDescriptionOptions& media_description_options,
1985 const MediaSessionOptions& session_options,
1986 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001987 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001988 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001989 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001990 SessionDescription* desc,
1991 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001992 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1993
kwiberg31022942016-03-11 14:18:21 -08001994 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07001995 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
1996 // If the DataChannel type is not specified, use the DataChannel type in
1997 // the current description.
1998 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001999 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002000 is_sctp = (current_content->media_description()->protocol() ==
2001 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002002 }
deadbeef44f08192015-12-15 16:20:09 -08002003
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002004 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002005 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2006 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002007 std::vector<std::string> crypto_suites;
2008 if (is_sctp) {
2009 // SDES doesn't make sense for SCTP, so we disable it, and we only
2010 // get SDES crypto suites for RTP-based data channels.
2011 sdes_policy = cricket::SEC_DISABLED;
2012 // Unlike SetMediaProtocol below, we need to set the protocol
2013 // before we call CreateMediaContentOffer. Otherwise,
2014 // CreateMediaContentOffer won't know this is SCTP and will
2015 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002016 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2017 // it's safe to do so. Older versions of webrtc would reject these
2018 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
Yves Gerey665174f2018-06-19 15:03:05 +02002019 data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
2020 : kMediaProtocolSctp);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002021 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002022 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002023 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002024 }
2025
zhihuang1c378ed2017-08-17 14:10:50 -07002026 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002027 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002028 media_description_options.sender_options, session_options,
2029 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2030 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002031 return false;
2032 }
2033
2034 if (is_sctp) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002035 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
zhihuang1c378ed2017-08-17 14:10:50 -07002036 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002037 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002038 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002039 SetMediaProtocol(secure_transport, data.get());
Steve Anton5adfafd2017-12-20 16:34:00 -08002040 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
zhihuang1c378ed2017-08-17 14:10:50 -07002041 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 }
zhihuang1c378ed2017-08-17 14:10:50 -07002043 if (!AddTransportOffer(media_description_options.mid,
2044 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002045 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002046 return false;
2047 }
2048 return true;
2049}
2050
zhihuang1c378ed2017-08-17 14:10:50 -07002051// |audio_codecs| = set of all possible codecs that can be used, with correct
2052// payload type mappings
2053//
2054// |supported_audio_codecs| = set of codecs that are supported for the direction
2055// of this m= section
2056//
2057// acd->codecs() = set of previously negotiated codecs for this m= section
2058//
2059// The payload types should come from audio_codecs, but the order should come
2060// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2061// change existing codec priority, and that new codecs are added with the right
2062// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002063bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002064 const MediaDescriptionOptions& media_description_options,
2065 const MediaSessionOptions& session_options,
2066 const ContentInfo* offer_content,
2067 const SessionDescription* offer_description,
2068 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002069 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002070 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002071 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002072 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002073 SessionDescription* answer,
2074 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002075 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002076 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002077 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002078
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002079 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
2080 media_description_options.mid, offer_description,
2081 media_description_options.transport_options, current_description,
2082 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002083 if (!audio_transport) {
2084 return false;
2085 }
2086
zhihuang1c378ed2017-08-17 14:10:50 -07002087 // Pick codecs based on the requested communications direction in the offer
2088 // and the selected direction in the answer.
2089 // Note these will be filtered one final time in CreateMediaContentAnswer.
2090 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002091 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002092 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002093 AudioCodecs supported_audio_codecs =
2094 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2095
2096 AudioCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08002097 // Add the codecs from current content if it exists and is not being recycled.
2098 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002099 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002100 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002101 current_content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07002102 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002103 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2104 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002105 filtered_codecs.push_back(codec);
2106 }
2107 }
2108 }
2109 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002110 for (const AudioCodec& codec : supported_audio_codecs) {
2111 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002112 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002113 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2114 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002115 // We should use the local codec with local parameters and the codec id
2116 // would be correctly mapped in |NegotiateCodecs|.
2117 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002118 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002119 }
2120
zhihuang1c378ed2017-08-17 14:10:50 -07002121 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2122 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002123 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002124 new AudioContentDescription());
2125 // Do not require or create SDES cryptos if DTLS is used.
2126 cricket::SecurePolicy sdes_policy =
2127 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2128 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002129 offer_audio_description, media_description_options, session_options,
2130 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton1b8773d2018-04-06 11:13:34 -07002131 audio_rtp_header_extensions(session_options.is_unified_plan),
2132 enable_encrypted_rtp_header_extensions_, current_streams,
2133 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002134 return false; // Fails the session setup.
2135 }
2136
deadbeefb7892532017-02-22 19:35:18 -08002137 bool secure = bundle_transport ? bundle_transport->description.secure()
2138 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002139 bool rejected = media_description_options.stopped ||
2140 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002141 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2142 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002143 if (!AddTransportAnswer(media_description_options.mid,
2144 *(audio_transport.get()), answer)) {
2145 return false;
2146 }
2147
2148 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002149 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2150 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002151 }
2152
zhihuang1c378ed2017-08-17 14:10:50 -07002153 answer->AddContent(media_description_options.mid, offer_content->type,
2154 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002155 return true;
2156}
2157
2158bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002159 const MediaDescriptionOptions& media_description_options,
2160 const MediaSessionOptions& session_options,
2161 const ContentInfo* offer_content,
2162 const SessionDescription* offer_description,
2163 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002164 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002165 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002166 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002167 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002168 SessionDescription* answer,
2169 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002170 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002171 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002172 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002173
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002174 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer(
2175 media_description_options.mid, offer_description,
2176 media_description_options.transport_options, current_description,
2177 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002178 if (!video_transport) {
2179 return false;
2180 }
2181
zhihuang1c378ed2017-08-17 14:10:50 -07002182 VideoCodecs filtered_codecs;
Steve Antondcc3c022017-12-22 16:02:54 -08002183 // Add the codecs from current content if it exists and is not being recycled.
2184 if (current_content && !current_content->rejected) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002185 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002186 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002187 current_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002188 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002189 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002190 nullptr)) {
2191 filtered_codecs.push_back(codec);
2192 }
2193 }
2194 }
2195 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002196 for (const VideoCodec& codec : video_codecs_) {
2197 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002198 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002199 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2200 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002201 // We should use the local codec with local parameters and the codec id
2202 // would be correctly mapped in |NegotiateCodecs|.
2203 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002204 }
2205 }
2206
2207 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2208 session_options.bundle_enabled;
2209
kwiberg31022942016-03-11 14:18:21 -08002210 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002211 new VideoContentDescription());
2212 // Do not require or create SDES cryptos if DTLS is used.
2213 cricket::SecurePolicy sdes_policy =
2214 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002215 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002216 offer_video_description, media_description_options, session_options,
2217 filtered_codecs, sdes_policy, GetCryptos(current_content),
Steve Anton1b8773d2018-04-06 11:13:34 -07002218 video_rtp_header_extensions(session_options.is_unified_plan),
2219 enable_encrypted_rtp_header_extensions_, current_streams,
2220 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002221 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002222 }
deadbeefb7892532017-02-22 19:35:18 -08002223 bool secure = bundle_transport ? bundle_transport->description.secure()
2224 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002225 bool rejected = media_description_options.stopped ||
2226 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002227 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2228 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002229 if (!AddTransportAnswer(media_description_options.mid,
2230 *(video_transport.get()), answer)) {
2231 return false;
2232 }
2233
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002234 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002235 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002236 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002237 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2238 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002239 }
zhihuang1c378ed2017-08-17 14:10:50 -07002240 answer->AddContent(media_description_options.mid, offer_content->type,
2241 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002242 return true;
2243}
2244
2245bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002246 const MediaDescriptionOptions& media_description_options,
2247 const MediaSessionOptions& session_options,
2248 const ContentInfo* offer_content,
2249 const SessionDescription* offer_description,
2250 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002251 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002252 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002253 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002254 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002255 SessionDescription* answer,
2256 IceCredentialsIterator* ice_credentials) const {
2257 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer(
2258 media_description_options.mid, offer_description,
2259 media_description_options.transport_options, current_description,
2260 bundle_transport != nullptr, ice_credentials));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002261 if (!data_transport) {
2262 return false;
2263 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002264
kwiberg31022942016-03-11 14:18:21 -08002265 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002266 new DataContentDescription());
2267 // Do not require or create SDES cryptos if DTLS is used.
2268 cricket::SecurePolicy sdes_policy =
2269 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002270 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2271 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002272 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2273 const DataContentDescription* offer_data_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002274 offer_content->media_description()->as_data();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002275 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002276 offer_data_description, media_description_options, session_options,
2277 data_codecs, sdes_policy, GetCryptos(current_content),
2278 RtpHeaderExtensions(), enable_encrypted_rtp_header_extensions_,
2279 current_streams, bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002280 return false; // Fails the session setup.
2281 }
2282
zstein4b2e0822017-02-17 19:48:38 -08002283 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002284 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2285 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2286
deadbeefb7892532017-02-22 19:35:18 -08002287 bool secure = bundle_transport ? bundle_transport->description.secure()
2288 : data_transport->secure();
2289
zhihuang1c378ed2017-08-17 14:10:50 -07002290 bool rejected = session_options.data_channel_type == DCT_NONE ||
2291 media_description_options.stopped ||
2292 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002293 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2294 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002295 if (!AddTransportAnswer(media_description_options.mid,
2296 *(data_transport.get()), answer)) {
2297 return false;
2298 }
2299
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002300 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002301 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002302 } else {
2303 // RFC 3264
2304 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002305 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306 }
zhihuang1c378ed2017-08-17 14:10:50 -07002307 answer->AddContent(media_description_options.mid, offer_content->type,
2308 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002309 return true;
2310}
2311
zhihuang1c378ed2017-08-17 14:10:50 -07002312void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2313 audio_sendrecv_codecs_.clear();
2314 all_audio_codecs_.clear();
2315 // Compute the audio codecs union.
2316 for (const AudioCodec& send : audio_send_codecs_) {
2317 all_audio_codecs_.push_back(send);
2318 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2319 send, nullptr)) {
2320 // It doesn't make sense to have an RTX codec we support sending but not
2321 // receiving.
2322 RTC_DCHECK(!IsRtxCodec(send));
2323 }
2324 }
2325 for (const AudioCodec& recv : audio_recv_codecs_) {
2326 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2327 recv, nullptr)) {
2328 all_audio_codecs_.push_back(recv);
2329 }
2330 }
2331 // Use NegotiateCodecs to merge our codec lists, since the operation is
2332 // essentially the same. Put send_codecs as the offered_codecs, which is the
2333 // order we'd like to follow. The reasoning is that encoding is usually more
2334 // expensive than decoding, and prioritizing a codec in the send list probably
2335 // means it's a codec we can handle efficiently.
2336 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2337 &audio_sendrecv_codecs_);
2338}
2339
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002341 return (content && (content->type == MediaProtocolType::kRtp ||
2342 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343}
2344
2345bool IsAudioContent(const ContentInfo* content) {
2346 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2347}
2348
2349bool IsVideoContent(const ContentInfo* content) {
2350 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2351}
2352
2353bool IsDataContent(const ContentInfo* content) {
2354 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2355}
2356
deadbeef0ed85b22016-02-23 17:24:52 -08002357const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2358 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002359 for (const ContentInfo& content : contents) {
2360 if (IsMediaContentOfType(&content, media_type)) {
2361 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362 }
2363 }
deadbeef0ed85b22016-02-23 17:24:52 -08002364 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365}
2366
2367const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2368 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2369}
2370
2371const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2372 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2373}
2374
2375const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2376 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2377}
2378
Steve Antonad7bffc2018-01-22 10:21:56 -08002379const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2380 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002381 if (sdesc == nullptr) {
2382 return nullptr;
2383 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384
2385 return GetFirstMediaContent(sdesc->contents(), media_type);
2386}
2387
2388const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2389 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2390}
2391
2392const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2393 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2394}
2395
2396const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2397 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2398}
2399
2400const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002401 const SessionDescription* sdesc,
2402 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002403 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002404 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002405}
2406
2407const AudioContentDescription* GetFirstAudioContentDescription(
2408 const SessionDescription* sdesc) {
2409 return static_cast<const AudioContentDescription*>(
2410 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2411}
2412
2413const VideoContentDescription* GetFirstVideoContentDescription(
2414 const SessionDescription* sdesc) {
2415 return static_cast<const VideoContentDescription*>(
2416 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2417}
2418
2419const DataContentDescription* GetFirstDataContentDescription(
2420 const SessionDescription* sdesc) {
2421 return static_cast<const DataContentDescription*>(
2422 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2423}
2424
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002425//
2426// Non-const versions of the above functions.
2427//
2428
Steve Anton36b29d12017-10-30 09:57:42 -07002429ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002430 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002431 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002432 if (IsMediaContentOfType(&content, media_type)) {
2433 return &content;
2434 }
2435 }
2436 return nullptr;
2437}
2438
Steve Anton36b29d12017-10-30 09:57:42 -07002439ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002440 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2441}
2442
Steve Anton36b29d12017-10-30 09:57:42 -07002443ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002444 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2445}
2446
Steve Anton36b29d12017-10-30 09:57:42 -07002447ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002448 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2449}
2450
Steve Antonad7bffc2018-01-22 10:21:56 -08002451ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2452 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002453 if (sdesc == nullptr) {
2454 return nullptr;
2455 }
2456
Steve Anton36b29d12017-10-30 09:57:42 -07002457 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002458}
2459
2460ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2461 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2462}
2463
2464ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2465 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2466}
2467
2468ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2469 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2470}
2471
2472MediaContentDescription* GetFirstMediaContentDescription(
2473 SessionDescription* sdesc,
2474 MediaType media_type) {
2475 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002476 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002477}
2478
2479AudioContentDescription* GetFirstAudioContentDescription(
2480 SessionDescription* sdesc) {
2481 return static_cast<AudioContentDescription*>(
2482 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2483}
2484
2485VideoContentDescription* GetFirstVideoContentDescription(
2486 SessionDescription* sdesc) {
2487 return static_cast<VideoContentDescription*>(
2488 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2489}
2490
2491DataContentDescription* GetFirstDataContentDescription(
2492 SessionDescription* sdesc) {
2493 return static_cast<DataContentDescription*>(
2494 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2495}
2496
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002497} // namespace cricket