blob: dd5a814865e9b816c8db347c7feb6ef42f3f36c3 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/media_session.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
Elad Alon157540a2019-02-08 23:37:52 +010013#include <algorithm>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Steve Anton64b626b2019-01-28 17:25:26 -080021#include "absl/algorithm/container.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020022#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020023#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "media/base/media_constants.h"
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +020027#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "p2p/base/p2p_constants.h"
29#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020030#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "pc/rtp_media_utils.h"
32#include "pc/srtp_filter.h"
Johannes Kron746dd0d2019-06-20 15:37:52 +020033#include "pc/used_ids.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/checks.h"
35#include "rtc_base/helpers.h"
36#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020037#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080038#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080041
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080042using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080043using webrtc::RtpTransceiverDirection;
44
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046
Benjamin Wrighta54daf12018-10-11 15:33:17 -070047void GetSupportedSdesCryptoSuiteNames(
48 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
49 const webrtc::CryptoOptions& crypto_options,
50 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070052 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080053 for (const auto crypto : crypto_suites) {
54 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
55 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080056}
Elad Alon157540a2019-02-08 23:37:52 +010057
terelius8c011e52016-04-26 05:28:11 -070058} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60namespace cricket {
61
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062// RTP Profile names
63// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
64// RFC4585
65const char kMediaProtocolAvpf[] = "RTP/AVPF";
66// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000067const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
68
deadbeeff3938292015-07-15 12:20:53 -070069// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
70// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071const char kMediaProtocolSavpf[] = "RTP/SAVPF";
72
deadbeef8b7e9ad2017-05-25 09:38:55 -070073// Note that the below functions support some protocol strings purely for
74// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
75// and Interoperability.
76
77static bool IsDtlsRtp(const std::string& protocol) {
78 // Most-likely values first.
79 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
80 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
81}
82
83static bool IsPlainRtp(const std::string& protocol) {
84 // Most-likely values first.
85 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
86 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
87}
88
Steve Anton1d03a752017-11-27 14:30:09 -080089static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
90 RtpTransceiverDirection offer,
91 RtpTransceiverDirection wants) {
92 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
93 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
94 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
95 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
96 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
97 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070098}
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100static bool IsMediaContentOfType(const ContentInfo* content,
101 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800102 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103 return false;
104 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800105 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106}
107
Yves Gerey665174f2018-06-19 15:03:05 +0200108static bool CreateCryptoParams(int tag,
109 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700110 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700111 int key_len;
112 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200113 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
114 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return false;
116 }
jbauchcb560652016-08-04 05:20:32 -0700117
118 int master_key_len = key_len + salt_len;
119 std::string master_key;
120 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
121 return false;
122 }
123
kwiberg352444f2016-11-28 15:58:53 -0800124 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700125 std::string key = rtc::Base64::Encode(master_key);
126
Steve Anton3a66edf2018-09-10 12:57:37 -0700127 crypto_out->tag = tag;
128 crypto_out->cipher_suite = cipher;
129 crypto_out->key_params = kInline;
130 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 return true;
132}
133
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700135 CryptoParamsVec* cryptos_out) {
136 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Steve Anton3a66edf2018-09-10 12:57:37 -0700138 cryptos_out->resize(size + 1);
139 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140}
141
142void AddMediaCryptos(const CryptoParamsVec& cryptos,
143 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700144 for (const CryptoParams& crypto : cryptos) {
145 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 }
147}
148
149bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
150 MediaContentDescription* media) {
151 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700152 for (const std::string& crypto_suite : crypto_suites) {
153 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 return false;
155 }
156 }
157 AddMediaCryptos(cryptos, media);
158 return true;
159}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
zhihuang1c378ed2017-08-17 14:10:50 -0700161const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800162 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700163 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800165 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
168bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
169 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700170 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800171 auto it = absl::c_find_if(
172 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700173 if (it == cryptos.end()) {
174 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700176 *crypto_out = *it;
177 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178}
179
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700180// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
181// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700182void GetSupportedAudioSdesCryptoSuites(
183 const webrtc::CryptoOptions& crypto_options,
184 std::vector<int>* crypto_suites) {
185 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
188 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700189 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700190 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
191 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800192 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193}
194
deadbeef7914b8c2017-04-21 03:23:33 -0700195void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700196 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800197 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700198 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
199 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200}
201
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700202void GetSupportedVideoSdesCryptoSuites(
203 const webrtc::CryptoOptions& crypto_options,
204 std::vector<int>* crypto_suites) {
205 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700206 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
207 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
208 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800209 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
deadbeef7914b8c2017-04-21 03:23:33 -0700212void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700213 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800214 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700215 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
216 crypto_options, crypto_suite_names);
217}
218
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700219void GetSupportedDataSdesCryptoSuites(
220 const webrtc::CryptoOptions& crypto_options,
221 std::vector<int>* crypto_suites) {
222 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700223 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
225 }
226 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
227}
228
229void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700230 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700231 std::vector<std::string>* crypto_suite_names) {
232 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
233 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800234}
235
jbauchcb560652016-08-04 05:20:32 -0700236// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700237// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
238// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700239// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240static bool SelectCrypto(const MediaContentDescription* offer,
241 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700242 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700243 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
245 const CryptoParamsVec& cryptos = offer->cryptos();
246
Steve Anton3a66edf2018-09-10 12:57:37 -0700247 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700248 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700249 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
250 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
251 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700252 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700253 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 }
255 }
256 return false;
257}
258
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800260static StreamParamsVec GetCurrentStreamParams(
261 const std::vector<const ContentInfo*>& active_local_contents) {
262 StreamParamsVec stream_params;
263 for (const ContentInfo* content : active_local_contents) {
264 for (const StreamParams& params : content->media_description()->streams()) {
265 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 }
267 }
Steve Anton5c72e712018-12-10 14:25:30 -0800268 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269}
270
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000271// Filters the data codecs for the data channel type.
272void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
273 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700274 const char* codec_name =
275 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700276 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
277 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200278 return absl::EqualsIgnoreCase(codec.name,
279 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700280 }),
281 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000282}
283
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800284static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
285 const SenderOptions& sender,
286 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800287 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800288 bool include_flexfec_stream,
289 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800290 StreamParams result;
291 result.id = sender.track_id;
292
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800293 // TODO(brandtr): Update when we support multistream protection.
294 if (include_flexfec_stream && sender.num_sim_layers > 1) {
295 include_flexfec_stream = false;
296 RTC_LOG(LS_WARNING)
297 << "Our FlexFEC implementation only supports protecting "
298 "a single media streams. This session has multiple "
299 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800300 }
301
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800302 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
303 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800304
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800305 result.cname = rtcp_cname;
306 result.set_stream_ids(sender.stream_ids);
307
308 return result;
309}
310
311static bool ValidateSimulcastLayers(
312 const std::vector<RidDescription>& rids,
313 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800314 return absl::c_all_of(
315 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
316 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
317 return rid.rid == layer.rid;
318 });
319 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800320}
321
322static StreamParams CreateStreamParamsForNewSenderWithRids(
323 const SenderOptions& sender,
324 const std::string& rtcp_cname) {
325 RTC_DCHECK(!sender.rids.empty());
326 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
327 << "RIDs are the compliant way to indicate simulcast.";
328 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
329 StreamParams result;
330 result.id = sender.track_id;
331 result.cname = rtcp_cname;
332 result.set_stream_ids(sender.stream_ids);
333
334 // More than one rid should be signaled.
335 if (sender.rids.size() > 1) {
336 result.set_rids(sender.rids);
337 }
338
339 return result;
340}
341
342// Adds SimulcastDescription if indicated by the media description options.
343// MediaContentDescription should already be set up with the send rids.
344static void AddSimulcastToMediaDescription(
345 const MediaDescriptionOptions& media_description_options,
346 MediaContentDescription* description) {
347 RTC_DCHECK(description);
348
349 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800350 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
351 return !params.has_rids();
352 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800353 return;
354 }
355
356 RTC_DCHECK_EQ(1, description->streams().size())
357 << "RIDs are only supported in Unified Plan semantics.";
358 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
359 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
360 description->type() == MediaType::MEDIA_TYPE_VIDEO);
361
362 // One RID or less indicates that simulcast is not needed.
363 if (description->streams()[0].rids().size() <= 1) {
364 return;
365 }
366
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800367 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800368 SimulcastDescription simulcast;
369 simulcast.send_layers() =
370 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800371 description->set_simulcast_description(simulcast);
372}
373
zhihuang1c378ed2017-08-17 14:10:50 -0700374// Adds a StreamParams for each SenderOptions in |sender_options| to
375// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000376// |current_params| - All currently known StreamParams of any media type.
377template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700378static bool AddStreamParams(
379 const std::vector<SenderOptions>& sender_options,
380 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800381 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700382 StreamParamsVec* current_streams,
383 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700384 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200385 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700386 return true;
387 }
388
Noah Richards2e7a0982015-05-18 14:02:54 -0700389 const bool include_rtx_streams =
390 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391
brandtr03d5fb12016-11-22 03:37:59 -0800392 const bool include_flexfec_stream =
393 ContainsFlexfecCodec(content_description->codecs());
394
zhihuang1c378ed2017-08-17 14:10:50 -0700395 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 // groupid is empty for StreamParams generated using
397 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700398 StreamParams* param =
399 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000400 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700401 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800402 StreamParams stream_param =
403 sender.rids.empty()
404 ?
405 // Signal SSRCs and legacy simulcast (if requested).
406 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800407 sender, rtcp_cname, include_rtx_streams,
408 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800409 :
410 // Signal RIDs and spec-compliant simulcast (if requested).
411 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
412
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413 content_description->AddStream(stream_param);
414
415 // Store the new StreamParams in current_streams.
416 // This is necessary so that we can use the CNAME for other media types.
417 current_streams->push_back(stream_param);
418 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700419 // Use existing generated SSRCs/groups, but update the sync_label if
420 // necessary. This may be needed if a MediaStreamTrack was moved from one
421 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800422 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000423 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 }
425 }
426 return true;
427}
428
429// Updates the transport infos of the |sdesc| according to the given
430// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800431// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
432// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
434 SessionDescription* sdesc) {
435 // The bundle should not be empty.
436 if (!sdesc || !bundle_group.FirstContentName()) {
437 return false;
438 }
439
440 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700441 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 const TransportInfo* selected_transport_info =
443 sdesc->GetTransportInfoByName(selected_content_name);
444 if (!selected_transport_info) {
445 return false;
446 }
447
448 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700449 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700451 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800453 ConnectionRole selected_connection_role =
454 selected_transport_info->description.connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700455 const absl::optional<OpaqueTransportParameters>& selected_opaque_parameters =
456 selected_transport_info->description.opaque_parameters;
Steve Anton3a66edf2018-09-10 12:57:37 -0700457 for (TransportInfo& transport_info : sdesc->transport_infos()) {
458 if (bundle_group.HasContentName(transport_info.content_name) &&
459 transport_info.content_name != selected_content_name) {
460 transport_info.description.ice_ufrag = selected_ufrag;
461 transport_info.description.ice_pwd = selected_pwd;
462 transport_info.description.connection_role = selected_connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700463 transport_info.description.opaque_parameters = selected_opaque_parameters;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 }
465 }
466 return true;
467}
468
469// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
470// sets it to |cryptos|.
471static bool GetCryptosByName(const SessionDescription* sdesc,
472 const std::string& content_name,
473 CryptoParamsVec* cryptos) {
474 if (!sdesc || !cryptos) {
475 return false;
476 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800478 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479 return false;
480 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800481 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000482 return true;
483}
484
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
486// which are not available in |filter|.
487static void PruneCryptos(const CryptoParamsVec& filter,
488 CryptoParamsVec* target_cryptos) {
489 if (!target_cryptos) {
490 return;
491 }
tzik21995802018-04-26 17:38:28 +0900492
493 target_cryptos->erase(
494 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
495 // Returns true if the |crypto|'s cipher_suite is not
496 // found in |filter|.
497 [&filter](const CryptoParams& crypto) {
498 for (const CryptoParams& entry : filter) {
499 if (entry.cipher_suite == crypto.cipher_suite)
500 return false;
501 }
502 return true;
503 }),
504 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505}
506
507static bool IsRtpContent(SessionDescription* sdesc,
508 const std::string& content_name) {
509 bool is_rtp = false;
510 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800511 if (content && content->media_description()) {
512 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 }
514 return is_rtp;
515}
516
517// Updates the crypto parameters of the |sdesc| according to the given
518// |bundle_group|. The crypto parameters of all the contents within the
519// |bundle_group| should be updated to use the common subset of the
520// available cryptos.
521static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
522 SessionDescription* sdesc) {
523 // The bundle should not be empty.
524 if (!sdesc || !bundle_group.FirstContentName()) {
525 return false;
526 }
527
wu@webrtc.org78187522013-10-07 23:32:02 +0000528 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 // Get the common cryptos.
530 const ContentNames& content_names = bundle_group.content_names();
531 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700532 bool first = true;
533 for (const std::string& content_name : content_names) {
534 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 continue;
536 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000537 // The common cryptos are needed if any of the content does not have DTLS
538 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700539 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000540 common_cryptos_needed = true;
541 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700542 if (first) {
543 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700545 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 return false;
547 }
548 if (common_cryptos.empty()) {
549 // If there's no crypto params, we should just return.
550 return true;
551 }
552 } else {
553 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700554 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 return false;
556 }
557 PruneCryptos(cryptos, &common_cryptos);
558 }
559 }
560
wu@webrtc.org78187522013-10-07 23:32:02 +0000561 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 return false;
563 }
564
565 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700566 for (const std::string& content_name : content_names) {
567 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 continue;
569 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700570 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800572 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 if (!media_desc) {
574 return false;
575 }
576 media_desc->set_cryptos(common_cryptos);
577 }
578 }
579 return true;
580}
581
Steve Anton5c72e712018-12-10 14:25:30 -0800582static std::vector<const ContentInfo*> GetActiveContents(
583 const SessionDescription& description,
584 const MediaSessionOptions& session_options) {
585 std::vector<const ContentInfo*> active_contents;
586 for (size_t i = 0; i < description.contents().size(); ++i) {
587 RTC_DCHECK_LT(i, session_options.media_description_options.size());
588 const ContentInfo& content = description.contents()[i];
589 const MediaDescriptionOptions& media_options =
590 session_options.media_description_options[i];
591 if (!content.rejected && !media_options.stopped &&
592 content.name == media_options.mid) {
593 active_contents.push_back(&content);
594 }
595 }
596 return active_contents;
597}
598
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599template <class C>
600static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800601 for (const auto& codec : codecs) {
602 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 return true;
604 }
605 }
606 return false;
607}
608
609template <class C>
610static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200611 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612}
613
brandtr03d5fb12016-11-22 03:37:59 -0800614template <class C>
615static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
616 for (const auto& codec : codecs) {
617 if (IsFlexfecCodec(codec)) {
618 return true;
619 }
620 }
621 return false;
622}
623
624template <class C>
625static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200626 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800627}
628
zhihuang1c378ed2017-08-17 14:10:50 -0700629// Create a media content to be offered for the given |sender_options|,
630// according to the given options.rtcp_mux, session_options.is_muc, codecs,
631// secure_transport, crypto, and current_streams. If we don't currently have
632// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
633// created (according to crypto_suites). The created content is added to the
634// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200635static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800636 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700637 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000638 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 const CryptoParamsVec* current_cryptos,
640 const std::vector<std::string>& crypto_suites,
641 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800642 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200644 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700645 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700646 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
647 offer->set_rtcp_reduced_size(true);
648 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 offer->set_rtp_header_extensions(rtp_extensions);
650
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800651 AddSimulcastToMediaDescription(media_description_options, offer);
652
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 if (secure_policy != SEC_DISABLED) {
654 if (current_cryptos) {
655 AddMediaCryptos(*current_cryptos, offer);
656 }
657 if (offer->cryptos().empty()) {
658 if (!CreateMediaCryptos(crypto_suites, offer)) {
659 return false;
660 }
661 }
662 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700664 offer->set_alt_protocol(media_description_options.alt_protocol);
665
deadbeef7af91dd2016-12-13 11:29:11 -0800666 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 return false;
668 }
669 return true;
670}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200671template <class C>
672static bool CreateMediaContentOffer(
673 const MediaDescriptionOptions& media_description_options,
674 const MediaSessionOptions& session_options,
675 const std::vector<C>& codecs,
676 const SecurePolicy& secure_policy,
677 const CryptoParamsVec* current_cryptos,
678 const std::vector<std::string>& crypto_suites,
679 const RtpHeaderExtensions& rtp_extensions,
680 UniqueRandomIdGenerator* ssrc_generator,
681 StreamParamsVec* current_streams,
682 MediaContentDescriptionImpl<C>* offer) {
683 offer->AddCodecs(codecs);
684 if (!AddStreamParams(media_description_options.sender_options,
685 session_options.rtcp_cname, ssrc_generator,
686 current_streams, offer)) {
687 return false;
688 }
689
690 return CreateContentOffer(media_description_options, session_options,
691 secure_policy, current_cryptos, crypto_suites,
692 rtp_extensions, ssrc_generator, current_streams,
693 offer);
694}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000695
696template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000697static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800698 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000699 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800700 const int codec2_id) {
701 const C* codec1 = FindCodecById(codecs1, codec1_id);
702 const C* codec2 = FindCodecById(codecs2, codec2_id);
703 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000704}
705
706template <class C>
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200707static void NegotiatePacketization(const C& local_codec,
708 const C& remote_codec,
709 C* negotiated_codec) {}
710
711template <>
712void NegotiatePacketization(const VideoCodec& local_codec,
713 const VideoCodec& remote_codec,
714 VideoCodec* negotiated_codec) {
715 negotiated_codec->packetization =
716 VideoCodec::IntersectPacketization(local_codec, remote_codec);
717}
718
719template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720static void NegotiateCodecs(const std::vector<C>& local_codecs,
721 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200722 std::vector<C>* negotiated_codecs,
723 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800724 for (const C& ours : local_codecs) {
725 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700726 // Note that we intentionally only find one matching codec for each of our
727 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800728 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
729 C negotiated = ours;
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200730 NegotiatePacketization(ours, theirs, &negotiated);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800731 negotiated.IntersectFeedbackParams(theirs);
732 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800733 const auto apt_it =
734 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800735 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800736 RTC_DCHECK(apt_it != theirs.params.end());
737 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 }
Niels Möller039743e2018-10-23 10:07:25 +0200739 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800740 webrtc::H264::GenerateProfileLevelIdForAnswer(
741 ours.params, theirs.params, &negotiated.params);
742 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800743 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700744 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800745 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 }
747 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200748 if (keep_offer_order) {
749 // RFC3264: Although the answerer MAY list the formats in their desired
750 // order of preference, it is RECOMMENDED that unless there is a
751 // specific reason, the answerer list formats in the same relative order
752 // they were present in the offer.
753 // This can be skipped when the transceiver has any codec preferences.
754 std::unordered_map<int, int> payload_type_preferences;
755 int preference = static_cast<int>(offered_codecs.size() + 1);
756 for (const C& codec : offered_codecs) {
757 payload_type_preferences[codec.id] = preference--;
758 }
759 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
760 const C& b) {
761 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
762 });
deadbeef67cf2c12016-04-13 10:07:16 -0700763 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764}
765
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800766// Finds a codec in |codecs2| that matches |codec_to_match|, which is
767// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
768// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800770static bool FindMatchingCodec(const std::vector<C>& codecs1,
771 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 const C& codec_to_match,
773 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700774 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
775 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800776 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
777 return &codec == &codec_to_match;
778 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800779 for (const C& potential_match : codecs2) {
780 if (potential_match.Matches(codec_to_match)) {
781 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800782 int apt_value_1 = 0;
783 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800784 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
785 &apt_value_1) ||
786 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
787 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100788 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800789 continue;
790 }
791 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
792 apt_value_2)) {
793 continue;
794 }
795 }
796 if (found_codec) {
797 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 }
799 return true;
800 }
801 }
802 return false;
803}
804
zhihuang1c378ed2017-08-17 14:10:50 -0700805// Find the codec in |codec_list| that |rtx_codec| is associated with.
806template <class C>
807static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
808 const C& rtx_codec) {
809 std::string associated_pt_str;
810 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
811 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100812 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
813 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700814 return nullptr;
815 }
816
817 int associated_pt;
818 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100819 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
820 << " of RTX codec " << rtx_codec.name
821 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700822 return nullptr;
823 }
824
825 // Find the associated reference codec for the reference RTX codec.
826 const C* associated_codec = FindCodecById(codec_list, associated_pt);
827 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100828 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
829 << associated_pt << " for RTX codec " << rtx_codec.name
830 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700831 }
832 return associated_codec;
833}
834
835// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836// already exist in |offered_codecs| and ensure the payload types don't
837// collide.
838template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700839static void MergeCodecs(const std::vector<C>& reference_codecs,
840 std::vector<C>* offered_codecs,
841 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800843 for (const C& reference_codec : reference_codecs) {
844 if (!IsRtxCodec(reference_codec) &&
845 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
846 reference_codec, nullptr)) {
847 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 used_pltypes->FindAndSetIdUsed(&codec);
849 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 }
851 }
852
853 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800854 for (const C& reference_codec : reference_codecs) {
855 if (IsRtxCodec(reference_codec) &&
856 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
857 reference_codec, nullptr)) {
858 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700859 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700860 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700861 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700862 continue;
863 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800864 // Find a codec in the offered list that matches the reference codec.
865 // Its payload type may be different than the reference codec.
866 C matching_codec;
867 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800868 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100869 RTC_LOG(LS_WARNING)
870 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800871 continue;
872 }
873
874 rtx_codec.params[kCodecParamAssociatedPayloadType] =
875 rtc::ToString(matching_codec.id);
876 used_pltypes->FindAndSetIdUsed(&rtx_codec);
877 offered_codecs->push_back(rtx_codec);
878 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 }
880}
881
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200882template <typename Codecs>
883static Codecs MatchCodecPreference(
884 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
885 const Codecs& codecs) {
886 Codecs filtered_codecs;
887 std::set<std::string> kept_codecs_ids;
888 bool want_rtx = false;
889
890 for (const auto& codec_preference : codec_preferences) {
891 auto found_codec = absl::c_find_if(
892 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
893 webrtc::RtpCodecParameters codec_parameters =
894 codec.ToCodecParameters();
895 return codec_parameters.name == codec_preference.name &&
896 codec_parameters.kind == codec_preference.kind &&
897 codec_parameters.num_channels ==
898 codec_preference.num_channels &&
899 codec_parameters.clock_rate == codec_preference.clock_rate &&
900 codec_parameters.parameters == codec_preference.parameters;
901 });
902
903 if (found_codec != codecs.end()) {
904 filtered_codecs.push_back(*found_codec);
905 kept_codecs_ids.insert(std::to_string(found_codec->id));
906 } else if (IsRtxCodec(codec_preference)) {
907 want_rtx = true;
908 }
909 }
910
911 if (want_rtx) {
912 for (const auto& codec : codecs) {
913 if (IsRtxCodec(codec)) {
914 const auto apt =
915 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
916 if (apt != codec.params.end() &&
917 kept_codecs_ids.count(apt->second) > 0) {
918 filtered_codecs.push_back(codec);
919 }
920 }
921 }
922 }
923
924 return filtered_codecs;
925}
926
zhihuang1c378ed2017-08-17 14:10:50 -0700927static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
928 const webrtc::RtpExtension& ext_to_match,
929 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800930 auto it = absl::c_find_if(
931 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
932 // We assume that all URIs are given in a canonical
933 // format.
934 return extension.uri == ext_to_match.uri &&
935 extension.encrypt == ext_to_match.encrypt;
936 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700937 if (it == extensions.end()) {
938 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700939 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700940 if (found_extension) {
941 *found_extension = *it;
942 }
943 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700944}
945
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000946static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700947 const webrtc::RtpExtension& ext_to_match,
948 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700949 // We assume that all URIs are given in a canonical format.
950 const webrtc::RtpExtension* found =
951 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
952 ext_to_match.uri);
953 if (!found) {
954 return false;
955 }
956 if (found_extension) {
957 *found_extension = *found;
958 }
959 return true;
960}
961
962static bool FindByUriWithEncryptionPreference(
963 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200964 const webrtc::RtpExtension& ext_to_match,
965 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700966 webrtc::RtpExtension* found_extension) {
967 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700968 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700970 if (extension.uri == ext_to_match.uri) {
971 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700972 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700973 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700974 }
975 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700977 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978 }
979 }
jbauch5869f502017-06-29 12:31:36 -0700980 if (unencrypted_extension) {
981 if (found_extension) {
982 *found_extension = *unencrypted_extension;
983 }
984 return true;
985 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 return false;
987}
988
zhihuang1c378ed2017-08-17 14:10:50 -0700989// Adds all extensions from |reference_extensions| to |offered_extensions| that
990// don't already exist in |offered_extensions| and ensure the IDs don't
991// collide. If an extension is added, it's also added to |regular_extensions| or
992// |encrypted_extensions|, and if the extension is in |regular_extensions| or
993// |encrypted_extensions|, its ID is marked as used in |used_ids|.
994// |offered_extensions| is for either audio or video while |regular_extensions|
995// and |encrypted_extensions| are used for both audio and video. There could be
996// overlap between audio extensions and video extensions.
997static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
998 RtpHeaderExtensions* offered_extensions,
999 RtpHeaderExtensions* regular_extensions,
1000 RtpHeaderExtensions* encrypted_extensions,
1001 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001002 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001003 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1004 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001005 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001006 if (reference_extension.encrypt) {
1007 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1008 &existing)) {
1009 offered_extensions->push_back(existing);
1010 } else {
1011 used_ids->FindAndSetIdUsed(&reference_extension);
1012 encrypted_extensions->push_back(reference_extension);
1013 offered_extensions->push_back(reference_extension);
1014 }
olka3c747662017-08-17 06:50:32 -07001015 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001016 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1017 &existing)) {
1018 offered_extensions->push_back(existing);
1019 } else {
1020 used_ids->FindAndSetIdUsed(&reference_extension);
1021 regular_extensions->push_back(reference_extension);
1022 offered_extensions->push_back(reference_extension);
1023 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001024 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025 }
1026 }
1027}
1028
jbauch5869f502017-06-29 12:31:36 -07001029static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1030 RtpHeaderExtensions* all_extensions,
1031 UsedRtpHeaderExtensionIds* used_ids) {
1032 RtpHeaderExtensions encrypted_extensions;
1033 for (const webrtc::RtpExtension& extension : *extensions) {
1034 webrtc::RtpExtension existing;
1035 // Don't add encrypted extensions again that were already included in a
1036 // previous offer or regular extensions that are also included as encrypted
1037 // extensions.
1038 if (extension.encrypt ||
1039 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1040 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001041 &existing) &&
1042 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001043 continue;
1044 }
1045
1046 if (FindByUri(*all_extensions, extension, &existing)) {
1047 encrypted_extensions.push_back(existing);
1048 } else {
1049 webrtc::RtpExtension encrypted(extension);
1050 encrypted.encrypt = true;
1051 used_ids->FindAndSetIdUsed(&encrypted);
1052 all_extensions->push_back(encrypted);
1053 encrypted_extensions.push_back(encrypted);
1054 }
1055 }
1056 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001057 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001058}
1059
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060static void NegotiateRtpHeaderExtensions(
1061 const RtpHeaderExtensions& local_extensions,
1062 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001063 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001064 RtpHeaderExtensions* negotiated_extensions) {
1065 // TransportSequenceNumberV2 is not offered by default. The special logic for
1066 // the TransportSequenceNumber extensions works as follows:
1067 // Offer Answer
1068 // V1 V1 if in local_extensions.
1069 // V1 and V2 V2 regardless of local_extensions.
1070 // V2 V2 regardless of local_extensions.
1071 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1072 webrtc::RtpExtension::FindHeaderExtensionByUri(
1073 offered_extensions,
1074 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1075
Steve Anton3a66edf2018-09-10 12:57:37 -07001076 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001077 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001078 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001079 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001080 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001081 if (transport_sequence_number_v2_offer &&
1082 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1083 // Don't respond to
1084 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1085 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001086 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001087 continue;
1088 } else {
1089 // We respond with their RTP header extension id.
1090 negotiated_extensions->push_back(theirs);
1091 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 }
1093 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001094
1095 if (transport_sequence_number_v2_offer) {
1096 // Respond that we support kTransportSequenceNumberV2Uri.
1097 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1098 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099}
1100
1101static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001102 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1103 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001104 return absl::EqualsIgnoreCase(
1105 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001106 }),
1107 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108}
1109
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001110template <class C>
1111static bool SetCodecsInAnswer(
1112 const MediaContentDescriptionImpl<C>* offer,
1113 const std::vector<C>& local_codecs,
1114 const MediaDescriptionOptions& media_description_options,
1115 const MediaSessionOptions& session_options,
1116 UniqueRandomIdGenerator* ssrc_generator,
1117 StreamParamsVec* current_streams,
1118 MediaContentDescriptionImpl<C>* answer) {
1119 std::vector<C> negotiated_codecs;
1120 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1121 media_description_options.codec_preferences.empty());
1122 answer->AddCodecs(negotiated_codecs);
1123 answer->set_protocol(offer->protocol());
1124 if (!AddStreamParams(media_description_options.sender_options,
1125 session_options.rtcp_cname, ssrc_generator,
1126 current_streams, answer)) {
1127 return false; // Something went seriously wrong.
1128 }
1129 return true;
1130}
1131
zhihuang1c378ed2017-08-17 14:10:50 -07001132// Create a media content to be answered for the given |sender_options|
1133// according to the given session_options.rtcp_mux, session_options.streams,
1134// codecs, crypto, and current_streams. If we don't currently have crypto (in
1135// current_cryptos) and it is enabled (in secure_policy), crypto is created
1136// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1137// negotiated with the offer. If the negotiation fails, this method returns
1138// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001140 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001141 const MediaDescriptionOptions& media_description_options,
1142 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001143 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 const CryptoParamsVec* current_cryptos,
1145 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001146 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001147 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001149 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001150 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001151 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001153 NegotiateRtpHeaderExtensions(
1154 local_rtp_extenstions, offer->rtp_header_extensions(),
1155 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1157
zhihuang1c378ed2017-08-17 14:10:50 -07001158 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001159 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1160 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1161 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162
Sebastian Janssone1795f42019-07-24 11:38:03 +02001163 answer->set_remote_estimate(offer->remote_estimate());
1164
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165 if (sdes_policy != SEC_DISABLED) {
1166 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001167 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1168 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 if (current_cryptos) {
1170 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1171 }
1172 answer->AddCrypto(crypto);
1173 }
1174 }
1175
deadbeef7af91dd2016-12-13 11:29:11 -08001176 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 return false;
1178 }
1179
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001180 AddSimulcastToMediaDescription(media_description_options, answer);
1181
Steve Anton4e70a722017-11-28 14:57:10 -08001182 answer->set_direction(NegotiateRtpTransceiverDirection(
1183 offer->direction(), media_description_options.direction));
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07001184
1185 if (offer->alt_protocol() == media_description_options.alt_protocol) {
1186 answer->set_alt_protocol(media_description_options.alt_protocol);
1187 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188 return true;
1189}
1190
1191static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001192 const std::string& protocol,
1193 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001194 // Since not all applications serialize and deserialize the media protocol,
1195 // we will have to accept |protocol| to be empty.
1196 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 return true;
1198 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001199
zhihuangcf5b37c2016-05-05 11:44:35 -07001200 if (type == MEDIA_TYPE_DATA) {
1201 // Check for SCTP, but also for RTP for RTP-based data channels.
1202 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1203 if (secure_transport) {
1204 // Most likely scenarios first.
1205 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1206 IsPlainRtp(protocol);
1207 } else {
1208 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1209 }
1210 }
1211
1212 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1213 // JSEP specifies.
1214 if (secure_transport) {
1215 // Most likely scenarios first.
1216 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1217 } else {
1218 return IsPlainRtp(protocol);
1219 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001220}
1221
1222static void SetMediaProtocol(bool secure_transport,
1223 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001224 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001226 else if (secure_transport)
1227 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228 else
1229 desc->set_protocol(kMediaProtocolAvpf);
1230}
1231
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001232// Gets the TransportInfo of the given |content_name| from the
1233// |current_description|. If doesn't exist, returns a new one.
1234static const TransportDescription* GetTransportDescription(
1235 const std::string& content_name,
1236 const SessionDescription* current_description) {
1237 const TransportDescription* desc = NULL;
1238 if (current_description) {
1239 const TransportInfo* info =
1240 current_description->GetTransportInfoByName(content_name);
1241 if (info) {
1242 desc = &info->description;
1243 }
1244 }
1245 return desc;
1246}
1247
1248// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001249static bool IsDtlsActive(const ContentInfo* content,
1250 const SessionDescription* current_description) {
1251 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001252 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001253 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001254
zhihuang1c378ed2017-08-17 14:10:50 -07001255 size_t msection_index = content - &current_description->contents()[0];
1256
1257 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001258 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001259 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001260
zhihuang1c378ed2017-08-17 14:10:50 -07001261 return current_description->transport_infos()[msection_index]
1262 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001263}
1264
Steve Anton8ffb9c32017-08-31 15:45:38 -07001265void MediaDescriptionOptions::AddAudioSender(
1266 const std::string& track_id,
1267 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001268 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001269 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001270}
1271
Steve Anton8ffb9c32017-08-31 15:45:38 -07001272void MediaDescriptionOptions::AddVideoSender(
1273 const std::string& track_id,
1274 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001275 const std::vector<RidDescription>& rids,
1276 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001277 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001278 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001279 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1280 << "RIDs are the compliant way to indicate simulcast.";
1281 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1282 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1283 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001284}
1285
zhihuang1c378ed2017-08-17 14:10:50 -07001286void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1287 const std::string& stream_id) {
1288 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001289 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1290 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001291 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292}
1293
Steve Anton8ffb9c32017-08-31 15:45:38 -07001294void MediaDescriptionOptions::AddSenderInternal(
1295 const std::string& track_id,
1296 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001297 const std::vector<RidDescription>& rids,
1298 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001299 int num_sim_layers) {
1300 // TODO(steveanton): Support any number of stream ids.
1301 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001302 SenderOptions options;
1303 options.track_id = track_id;
1304 options.stream_ids = stream_ids;
1305 options.simulcast_layers = simulcast_layers;
1306 options.rids = rids;
1307 options.num_sim_layers = num_sim_layers;
1308 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309}
1310
zhihuang1c378ed2017-08-17 14:10:50 -07001311bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001312 return absl::c_any_of(
1313 media_description_options,
1314 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001315}
1316
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001318 const TransportDescriptionFactory* transport_desc_factory,
1319 rtc::UniqueRandomIdGenerator* ssrc_generator)
1320 : ssrc_generator_(ssrc_generator),
1321 transport_desc_factory_(transport_desc_factory) {
1322 RTC_DCHECK(ssrc_generator_);
1323}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324
1325MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1326 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001327 const TransportDescriptionFactory* transport_desc_factory,
1328 rtc::UniqueRandomIdGenerator* ssrc_generator)
1329 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001330 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1331 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001333 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001334 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001335 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001336 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001337}
1338
ossudedfd282016-06-14 07:12:39 -07001339const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1340 const {
ossu075af922016-06-14 03:29:38 -07001341 return audio_sendrecv_codecs_;
1342}
1343
1344const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1345 return audio_send_codecs_;
1346}
1347
1348const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1349 return audio_recv_codecs_;
1350}
1351
1352void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001353 const AudioCodecs& send_codecs,
1354 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001355 audio_send_codecs_ = send_codecs;
1356 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001357 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001358}
1359
Amit Hilbuch77938e62018-12-21 09:23:38 -08001360static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1361 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001362
1363 rtc::UniqueNumberGenerator<int> unique_id_generator;
1364 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1365 for (const webrtc::RtpExtension& extension : *extensions) {
1366 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1367 RTC_DCHECK(collision_free);
1368 }
1369
Amit Hilbuch77938e62018-12-21 09:23:38 -08001370 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001371 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1372 unique_id_generator()));
1373 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1374 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001375 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001376 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001377}
1378
1379RtpHeaderExtensions
1380MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1381 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1382 if (is_unified_plan_) {
1383 AddUnifiedPlanExtensions(&extensions);
1384 }
1385
1386 return extensions;
1387}
1388
1389RtpHeaderExtensions
1390MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1391 RtpHeaderExtensions extensions = video_rtp_extensions_;
1392 if (is_unified_plan_) {
1393 AddUnifiedPlanExtensions(&extensions);
1394 }
1395
1396 return extensions;
1397}
1398
Steve Anton6fe1fba2018-12-11 10:15:23 -08001399std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001400 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001401 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001402 // Must have options for each existing section.
1403 if (current_description) {
1404 RTC_DCHECK_LE(current_description->contents().size(),
1405 session_options.media_description_options.size());
1406 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001407
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001408 IceCredentialsIterator ice_credentials(
1409 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001410
1411 std::vector<const ContentInfo*> current_active_contents;
1412 if (current_description) {
1413 current_active_contents =
1414 GetActiveContents(*current_description, session_options);
1415 }
1416
1417 StreamParamsVec current_streams =
1418 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001419
zhihuang1c378ed2017-08-17 14:10:50 -07001420 AudioCodecs offer_audio_codecs;
1421 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001422 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001423 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001424 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001425
zhihuang1c378ed2017-08-17 14:10:50 -07001426 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001428 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001429 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001430 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001431 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432
1433 RtpHeaderExtensions audio_rtp_extensions;
1434 RtpHeaderExtensions video_rtp_extensions;
Johannes Kron746dd0d2019-06-20 15:37:52 +02001435 GetRtpHdrExtsToOffer(current_active_contents,
1436 session_options.offer_extmap_allow_mixed,
1437 &audio_rtp_extensions, &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001439 auto offer = std::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001440
zhihuang1c378ed2017-08-17 14:10:50 -07001441 // Iterate through the media description options, matching with existing media
1442 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001443 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001444 for (const MediaDescriptionOptions& media_description_options :
1445 session_options.media_description_options) {
1446 const ContentInfo* current_content = nullptr;
1447 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001448 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001449 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001450 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001451 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001452 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001453 media_description_options.type));
1454 }
1455 switch (media_description_options.type) {
1456 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001457 if (!AddAudioContentForOffer(
1458 media_description_options, session_options, current_content,
1459 current_description, audio_rtp_extensions, offer_audio_codecs,
1460 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001461 return nullptr;
1462 }
1463 break;
1464 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001465 if (!AddVideoContentForOffer(
1466 media_description_options, session_options, current_content,
1467 current_description, video_rtp_extensions, offer_video_codecs,
1468 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001469 return nullptr;
1470 }
1471 break;
1472 case MEDIA_TYPE_DATA:
1473 if (!AddDataContentForOffer(media_description_options, session_options,
1474 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001475 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001476 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001477 return nullptr;
1478 }
1479 break;
1480 default:
1481 RTC_NOTREACHED();
1482 }
1483 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001484 }
1485
1486 // Bundle the contents together, if we've been asked to do so, and update any
1487 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001488 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001490 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001491 if (content.rejected) {
1492 continue;
1493 }
zhihuang1c378ed2017-08-17 14:10:50 -07001494 // TODO(deadbeef): There are conditions that make bundling two media
1495 // descriptions together illegal. For example, they use the same payload
1496 // type to represent different codecs, or same IDs for different header
1497 // extensions. We need to detect this and not try to bundle those media
1498 // descriptions together.
1499 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500 }
Steve Anton2bed3972019-01-04 17:04:30 -08001501 if (!offer_bundle.content_names().empty()) {
1502 offer->AddGroup(offer_bundle);
1503 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1504 RTC_LOG(LS_ERROR)
1505 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1506 return nullptr;
1507 }
1508 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1509 RTC_LOG(LS_ERROR)
1510 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1511 return nullptr;
1512 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001513 }
1514 }
Steve Antone831b8c2018-02-01 12:22:16 -08001515
1516 // The following determines how to signal MSIDs to ensure compatibility with
1517 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001518 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001519 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1520 // Plan answerers will look at a=msid and Plan B answerers will look at the
1521 // a=ssrc MSID line.
1522 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1523 cricket::kMsidSignalingSsrcAttribute);
1524 } else {
1525 // Plan B always signals MSID using a=ssrc lines.
1526 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1527 }
1528
Johannes Kron89f874e2018-11-12 10:25:48 +01001529 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1530
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001531 if (session_options.media_transport_settings.has_value()) {
1532 offer->AddMediaTransportSetting(
1533 session_options.media_transport_settings->transport_name,
1534 session_options.media_transport_settings->transport_setting);
1535 }
1536
Steve Anton6fe1fba2018-12-11 10:15:23 -08001537 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538}
1539
Steve Anton6fe1fba2018-12-11 10:15:23 -08001540std::unique_ptr<SessionDescription>
1541MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001542 const SessionDescription* offer,
1543 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001544 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001545 if (!offer) {
1546 return nullptr;
1547 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001548
Steve Anton5c72e712018-12-10 14:25:30 -08001549 // Must have options for exactly as many sections as in the offer.
1550 RTC_DCHECK_EQ(offer->contents().size(),
1551 session_options.media_description_options.size());
1552
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001553 IceCredentialsIterator ice_credentials(
1554 session_options.pooled_ice_credentials);
1555
Steve Anton5c72e712018-12-10 14:25:30 -08001556 std::vector<const ContentInfo*> current_active_contents;
1557 if (current_description) {
1558 current_active_contents =
1559 GetActiveContents(*current_description, session_options);
1560 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561
Steve Anton5c72e712018-12-10 14:25:30 -08001562 StreamParamsVec current_streams =
1563 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001564
zhihuang1c378ed2017-08-17 14:10:50 -07001565 // Get list of all possible codecs that respects existing payload type
1566 // mappings and uses a single payload type space.
1567 //
1568 // Note that these lists may be further filtered for each m= section; this
1569 // step is done just to establish the payload type mappings shared by all
1570 // sections.
1571 AudioCodecs answer_audio_codecs;
1572 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001573 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001574 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001575 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001576
1577 if (!session_options.vad_enabled) {
1578 // If application doesn't want CN codecs in answer.
1579 StripCNCodecs(&answer_audio_codecs);
1580 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001581 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001582 session_options.data_channel_type == DCT_SCTP);
1583
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001584 auto answer = std::make_unique<SessionDescription>();
Steve Anton5c72e712018-12-10 14:25:30 -08001585
1586 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1587 // group in the answer with the appropriate content names.
1588 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1589 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1590 // Transport info shared by the bundle group.
1591 std::unique_ptr<TransportInfo> bundle_transport;
1592
1593 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1594
zhihuang1c378ed2017-08-17 14:10:50 -07001595 // Iterate through the media description options, matching with existing
1596 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001597 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001598 for (const MediaDescriptionOptions& media_description_options :
1599 session_options.media_description_options) {
1600 const ContentInfo* offer_content = &offer->contents()[msection_index];
1601 // Media types and MIDs must match between the remote offer and the
1602 // MediaDescriptionOptions.
1603 RTC_DCHECK(
1604 IsMediaContentOfType(offer_content, media_description_options.type));
1605 RTC_DCHECK(media_description_options.mid == offer_content->name);
1606 const ContentInfo* current_content = nullptr;
1607 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001608 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001609 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001610 }
zhihuang1c378ed2017-08-17 14:10:50 -07001611 switch (media_description_options.type) {
1612 case MEDIA_TYPE_AUDIO:
1613 if (!AddAudioContentForAnswer(
1614 media_description_options, session_options, offer_content,
1615 offer, current_content, current_description,
1616 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001617 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001618 return nullptr;
1619 }
1620 break;
1621 case MEDIA_TYPE_VIDEO:
1622 if (!AddVideoContentForAnswer(
1623 media_description_options, session_options, offer_content,
1624 offer, current_content, current_description,
1625 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001626 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001627 return nullptr;
1628 }
1629 break;
1630 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001631 if (!AddDataContentForAnswer(
1632 media_description_options, session_options, offer_content,
1633 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001634 bundle_transport.get(), answer_rtp_data_codecs,
1635 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001636 return nullptr;
1637 }
1638 break;
1639 default:
1640 RTC_NOTREACHED();
1641 }
1642 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001643 // See if we can add the newly generated m= section to the BUNDLE group in
1644 // the answer.
1645 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001646 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001647 offer_bundle->HasContentName(added.name)) {
1648 answer_bundle.AddContentName(added.name);
1649 bundle_transport.reset(
1650 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001651 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001652 }
1653
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001654 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1655 // it's empty. RFC5888 says:
1656 //
1657 // A SIP entity that receives an offer that contains an "a=group" line
1658 // with semantics that are understood MUST return an answer that
1659 // contains an "a=group" line with the same semantics.
1660 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001661 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001662 }
deadbeefb7892532017-02-22 19:35:18 -08001663
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001664 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001665 // Share the same ICE credentials and crypto params across all contents,
1666 // as BUNDLE requires.
1667 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001668 RTC_LOG(LS_ERROR)
1669 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001670 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001672
deadbeefb7892532017-02-22 19:35:18 -08001673 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001674 RTC_LOG(LS_ERROR)
1675 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001676 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001677 }
1678 }
1679
Steve Antone831b8c2018-02-01 12:22:16 -08001680 // The following determines how to signal MSIDs to ensure compatibility with
1681 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001682 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001683 // Unified Plan needs to look at what the offer included to find the most
1684 // compatible answer.
1685 if (offer->msid_signaling() == 0) {
1686 // We end up here in one of three cases:
1687 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1688 // matter what we pick here.
1689 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1690 // it also doesn't matter what we pick here.
1691 // 3. Media that's either sendonly or inactive from the remote endpoint.
1692 // We don't have any information to say whether the endpoint is Plan B
1693 // or Unified Plan, so be conservative and send both.
1694 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1695 cricket::kMsidSignalingSsrcAttribute);
1696 } else if (offer->msid_signaling() ==
1697 (cricket::kMsidSignalingMediaSection |
1698 cricket::kMsidSignalingSsrcAttribute)) {
1699 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1700 // probably talking to a Unified Plan endpoint so respond with just
1701 // a=msid.
1702 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1703 } else {
1704 // Otherwise, it's clear which method the offerer is using so repeat that
1705 // back to them.
1706 answer->set_msid_signaling(offer->msid_signaling());
1707 }
1708 } else {
1709 // Plan B always signals MSID using a=ssrc lines.
1710 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1711 }
1712
Steve Anton6fe1fba2018-12-11 10:15:23 -08001713 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001714}
1715
ossu075af922016-06-14 03:29:38 -07001716const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1717 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001718 switch (direction) {
1719 // If stream is inactive - generate list as if sendrecv.
1720 case RtpTransceiverDirection::kSendRecv:
1721 case RtpTransceiverDirection::kInactive:
1722 return audio_sendrecv_codecs_;
1723 case RtpTransceiverDirection::kSendOnly:
1724 return audio_send_codecs_;
1725 case RtpTransceiverDirection::kRecvOnly:
1726 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001727 }
Steve Anton1d03a752017-11-27 14:30:09 -08001728 RTC_NOTREACHED();
1729 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001730}
1731
1732const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1733 const RtpTransceiverDirection& offer,
1734 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001735 switch (answer) {
1736 // For inactive and sendrecv answers, generate lists as if we were to accept
1737 // the offer's direction. See RFC 3264 Section 6.1.
1738 case RtpTransceiverDirection::kSendRecv:
1739 case RtpTransceiverDirection::kInactive:
1740 return GetAudioCodecsForOffer(
1741 webrtc::RtpTransceiverDirectionReversed(offer));
1742 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001743 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001744 case RtpTransceiverDirection::kRecvOnly:
1745 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001746 }
Steve Anton1d03a752017-11-27 14:30:09 -08001747 RTC_NOTREACHED();
1748 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001749}
1750
Steve Anton5c72e712018-12-10 14:25:30 -08001751void MergeCodecsFromDescription(
1752 const std::vector<const ContentInfo*>& current_active_contents,
1753 AudioCodecs* audio_codecs,
1754 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001755 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001756 UsedPayloadTypes* used_pltypes) {
1757 for (const ContentInfo* content : current_active_contents) {
1758 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001759 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001760 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001761 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001762 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001763 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001764 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001765 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001766 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001767 const RtpDataContentDescription* data =
1768 content->media_description()->as_rtp_data();
1769 if (data) {
1770 // Only relevant for RTP datachannels
1771 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1772 used_pltypes);
1773 }
zhihuang1c378ed2017-08-17 14:10:50 -07001774 }
1775 }
1776}
1777
1778// Getting codecs for an offer involves these steps:
1779//
1780// 1. Construct payload type -> codec mappings for current description.
1781// 2. Add any reference codecs that weren't already present
1782// 3. For each individual media description (m= section), filter codecs based
1783// on the directional attribute (happens in another method).
1784void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001785 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786 AudioCodecs* audio_codecs,
1787 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001788 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001790 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1791 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001792 UsedPayloadTypes used_pltypes;
1793 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001794 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795
Steve Anton5c72e712018-12-10 14:25:30 -08001796 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001797 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1798 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001799 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001800}
1801
1802// Getting codecs for an answer involves these steps:
1803//
1804// 1. Construct payload type -> codec mappings for current description.
1805// 2. Add any codecs from the offer that weren't already present.
1806// 3. Add any remaining codecs that weren't already present.
1807// 4. For each individual media description (m= section), filter codecs based
1808// on the directional attribute (happens in another method).
1809void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001810 const std::vector<const ContentInfo*>& current_active_contents,
1811 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001812 AudioCodecs* audio_codecs,
1813 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001814 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001815 // First - get all codecs from the current description if the media type
1816 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1817 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001818 UsedPayloadTypes used_pltypes;
1819 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001820 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001821
1822 // Second - filter out codecs that we don't support at all and should ignore.
1823 AudioCodecs filtered_offered_audio_codecs;
1824 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001825 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001826 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001827 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1828 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001829 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001830 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1831 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1832 filtered_offered_audio_codecs,
1833 offered_audio_codec, nullptr) &&
1834 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1835 offered_audio_codec, nullptr)) {
1836 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1837 }
1838 }
1839 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1840 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001841 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001842 for (const VideoCodec& offered_video_codec : video->codecs()) {
1843 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1844 filtered_offered_video_codecs,
1845 offered_video_codec, nullptr) &&
1846 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1847 offered_video_codec, nullptr)) {
1848 filtered_offered_video_codecs.push_back(offered_video_codec);
1849 }
1850 }
1851 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001852 const RtpDataContentDescription* data =
1853 content.media_description()->as_rtp_data();
1854 if (data) {
1855 // RTP data. This part is inactive for SCTP data.
1856 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1857 if (!FindMatchingCodec<RtpDataCodec>(
1858 data->codecs(), filtered_offered_rtp_data_codecs,
1859 offered_rtp_data_codec, nullptr) &&
1860 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1861 offered_rtp_data_codec,
1862 nullptr)) {
1863 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1864 }
zhihuang1c378ed2017-08-17 14:10:50 -07001865 }
1866 }
1867 }
1868 }
1869
Steve Anton5c72e712018-12-10 14:25:30 -08001870 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001871 // |remote_offer|.
1872 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1873 &used_pltypes);
1874 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1875 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001876 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001877 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001878}
1879
1880void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001881 const std::vector<const ContentInfo*>& current_active_contents,
Johannes Kron746dd0d2019-06-20 15:37:52 +02001882 bool extmap_allow_mixed,
zhihuang1c378ed2017-08-17 14:10:50 -07001883 RtpHeaderExtensions* offer_audio_extensions,
1884 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001885 // All header extensions allocated from the same range to avoid potential
1886 // issues when using BUNDLE.
Johannes Kron746dd0d2019-06-20 15:37:52 +02001887
1888 // Strictly speaking the SDP attribute extmap_allow_mixed signals that the
1889 // receiver supports an RTP stream where one- and two-byte RTP header
1890 // extensions are mixed. For backwards compatibility reasons it's used in
1891 // WebRTC to signal that two-byte RTP header extensions are supported.
1892 UsedRtpHeaderExtensionIds used_ids(
1893 extmap_allow_mixed ? UsedRtpHeaderExtensionIds::IdDomain::kTwoByteAllowed
1894 : UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly);
jbauch5869f502017-06-29 12:31:36 -07001895 RtpHeaderExtensions all_regular_extensions;
1896 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897
1898 // First - get all extensions from the current description if the media type
1899 // is used.
1900 // Add them to |used_ids| so the local ids are not reused if a new media
1901 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001902 for (const ContentInfo* content : current_active_contents) {
1903 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1904 const AudioContentDescription* audio =
1905 content->media_description()->as_audio();
1906 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1907 &all_regular_extensions, &all_encrypted_extensions,
1908 &used_ids);
1909 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1910 const VideoContentDescription* video =
1911 content->media_description()->as_video();
1912 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1913 &all_regular_extensions, &all_encrypted_extensions,
1914 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915 }
1916 }
1917
Steve Anton5c72e712018-12-10 14:25:30 -08001918 // Add our default RTP header extensions that are not in the current
1919 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001920 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1921 &all_regular_extensions, &all_encrypted_extensions,
1922 &used_ids);
1923 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1924 &all_regular_extensions, &all_encrypted_extensions,
1925 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001926
jbauch5869f502017-06-29 12:31:36 -07001927 // TODO(jbauch): Support adding encrypted header extensions to existing
1928 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001929 if (enable_encrypted_rtp_header_extensions_ &&
1930 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001931 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1932 &all_encrypted_extensions, &used_ids);
1933 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1934 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001935 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936}
1937
1938bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001939 const std::string& content_name,
1940 const TransportOptions& transport_options,
1941 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001942 SessionDescription* offer_desc,
1943 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001945 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946 const TransportDescription* current_tdesc =
1947 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001948 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001949 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1950 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001951 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001952 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1953 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954 }
Steve Anton06817cd2018-12-18 15:55:30 -08001955 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1956 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001957}
1958
Steve Anton1a9d3c32018-12-10 17:18:54 -08001959std::unique_ptr<TransportDescription>
1960MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 const std::string& content_name,
1962 const SessionDescription* offer_desc,
1963 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001964 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001965 bool require_transport_attributes,
1966 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001967 if (!transport_desc_factory_)
1968 return NULL;
1969 const TransportDescription* offer_tdesc =
1970 GetTransportDescription(content_name, offer_desc);
1971 const TransportDescription* current_tdesc =
1972 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001973 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1974 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001975 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976}
1977
1978bool MediaSessionDescriptionFactory::AddTransportAnswer(
1979 const std::string& content_name,
1980 const TransportDescription& transport_desc,
1981 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001982 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983 return true;
1984}
1985
zhihuang1c378ed2017-08-17 14:10:50 -07001986// |audio_codecs| = set of all possible codecs that can be used, with correct
1987// payload type mappings
1988//
1989// |supported_audio_codecs| = set of codecs that are supported for the direction
1990// of this m= section
1991//
1992// acd->codecs() = set of previously negotiated codecs for this m= section
1993//
1994// The payload types should come from audio_codecs, but the order should come
1995// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1996// change existing codec priority, and that new codecs are added with the right
1997// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001998bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001999 const MediaDescriptionOptions& media_description_options,
2000 const MediaSessionOptions& session_options,
2001 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002002 const SessionDescription* current_description,
2003 const RtpHeaderExtensions& audio_rtp_extensions,
2004 const AudioCodecs& audio_codecs,
2005 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002006 SessionDescription* desc,
2007 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002008 // Filter audio_codecs (which includes all codecs, with correctly remapped
2009 // payload types) based on transceiver direction.
2010 const AudioCodecs& supported_audio_codecs =
2011 GetAudioCodecsForOffer(media_description_options.direction);
2012
2013 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002014
2015 if (!media_description_options.codec_preferences.empty()) {
2016 // Add the codecs from the current transceiver's codec preferences.
2017 // They override any existing codecs from previous negotiations.
2018 filtered_codecs = MatchCodecPreference(
2019 media_description_options.codec_preferences, supported_audio_codecs);
2020 } else {
2021 // Add the codecs from current content if it exists and is not rejected nor
2022 // recycled.
2023 if (current_content && !current_content->rejected &&
2024 current_content->name == media_description_options.mid) {
2025 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2026 const AudioContentDescription* acd =
2027 current_content->media_description()->as_audio();
2028 for (const AudioCodec& codec : acd->codecs()) {
2029 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2030 nullptr)) {
2031 filtered_codecs.push_back(codec);
2032 }
zhihuang1c378ed2017-08-17 14:10:50 -07002033 }
2034 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002035 // Add other supported audio codecs.
2036 AudioCodec found_codec;
2037 for (const AudioCodec& codec : supported_audio_codecs) {
2038 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2039 codec, &found_codec) &&
2040 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2041 filtered_codecs, codec, nullptr)) {
2042 // Use the |found_codec| from |audio_codecs| because it has the
2043 // correctly mapped payload type.
2044 filtered_codecs.push_back(found_codec);
2045 }
zhihuang1c378ed2017-08-17 14:10:50 -07002046 }
2047 }
deadbeef44f08192015-12-15 16:20:09 -08002048
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002049 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002050 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2051 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052
kwiberg31022942016-03-11 14:18:21 -08002053 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002054 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002055 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2056 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002057 if (!CreateMediaContentOffer(media_description_options, session_options,
2058 filtered_codecs, sdes_policy,
2059 GetCryptos(current_content), crypto_suites,
2060 audio_rtp_extensions, ssrc_generator_,
2061 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002062 return false;
2063 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002064
2065 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2066 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002067
Steve Anton4e70a722017-11-28 14:57:10 -08002068 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002069
Steve Anton5adfafd2017-12-20 16:34:00 -08002070 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002071 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002072 if (!AddTransportOffer(media_description_options.mid,
2073 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002074 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002075 return false;
2076 }
2077
2078 return true;
2079}
2080
2081bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002082 const MediaDescriptionOptions& media_description_options,
2083 const MediaSessionOptions& session_options,
2084 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002085 const SessionDescription* current_description,
2086 const RtpHeaderExtensions& video_rtp_extensions,
2087 const VideoCodecs& video_codecs,
2088 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002089 SessionDescription* desc,
2090 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002091 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002092 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2093 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002094
kwiberg31022942016-03-11 14:18:21 -08002095 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002096 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002097 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2098 &crypto_suites);
2099
2100 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002101
2102 if (!media_description_options.codec_preferences.empty()) {
2103 // Add the codecs from the current transceiver's codec preferences.
2104 // They override any existing codecs from previous negotiations.
2105 filtered_codecs = MatchCodecPreference(
2106 media_description_options.codec_preferences, video_codecs_);
2107 } else {
2108 // Add the codecs from current content if it exists and is not rejected nor
2109 // recycled.
2110 if (current_content && !current_content->rejected &&
2111 current_content->name == media_description_options.mid) {
2112 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2113 const VideoContentDescription* vcd =
2114 current_content->media_description()->as_video();
2115 for (const VideoCodec& codec : vcd->codecs()) {
2116 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2117 nullptr)) {
2118 filtered_codecs.push_back(codec);
2119 }
zhihuang1c378ed2017-08-17 14:10:50 -07002120 }
2121 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002122 // Add other supported video codecs.
2123 VideoCodec found_codec;
2124 for (const VideoCodec& codec : video_codecs_) {
2125 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2126 &found_codec) &&
2127 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2128 nullptr)) {
2129 // Use the |found_codec| from |video_codecs| because it has the
2130 // correctly mapped payload type.
2131 filtered_codecs.push_back(found_codec);
2132 }
zhihuang1c378ed2017-08-17 14:10:50 -07002133 }
2134 }
2135
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002136 if (session_options.raw_packetization_for_video) {
2137 for (VideoCodec& codec : filtered_codecs) {
2138 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2139 codec.packetization = kPacketizationParamRaw;
2140 }
2141 }
2142 }
2143
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002144 if (!CreateMediaContentOffer(media_description_options, session_options,
2145 filtered_codecs, sdes_policy,
2146 GetCryptos(current_content), crypto_suites,
2147 video_rtp_extensions, ssrc_generator_,
2148 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002149 return false;
2150 }
2151
zhihuang1c378ed2017-08-17 14:10:50 -07002152 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002153
2154 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2155 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002156
Steve Anton4e70a722017-11-28 14:57:10 -08002157 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002158
Steve Anton5adfafd2017-12-20 16:34:00 -08002159 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002160 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002161 if (!AddTransportOffer(media_description_options.mid,
2162 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002163 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002164 return false;
2165 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002166 return true;
2167}
2168
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002169bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2170 const MediaDescriptionOptions& media_description_options,
2171 const MediaSessionOptions& session_options,
2172 const ContentInfo* current_content,
2173 const SessionDescription* current_description,
2174 StreamParamsVec* current_streams,
2175 SessionDescription* desc,
2176 IceCredentialsIterator* ice_credentials) const {
2177 std::unique_ptr<SctpDataContentDescription> data(
2178 new SctpDataContentDescription());
2179
2180 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2181
2182 cricket::SecurePolicy sdes_policy =
2183 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2184 : secure();
2185 std::vector<std::string> crypto_suites;
2186 // SDES doesn't make sense for SCTP, so we disable it, and we only
2187 // get SDES crypto suites for RTP-based data channels.
2188 sdes_policy = cricket::SEC_DISABLED;
2189 // Unlike SetMediaProtocol below, we need to set the protocol
2190 // before we call CreateMediaContentOffer. Otherwise,
2191 // CreateMediaContentOffer won't know this is SCTP and will
2192 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002193 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002194 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002195 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002196 data->set_max_message_size(kSctpSendBufferSize);
2197
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002198 if (!CreateContentOffer(media_description_options, session_options,
2199 sdes_policy, GetCryptos(current_content),
2200 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2201 current_streams, data.get())) {
2202 return false;
2203 }
2204
2205 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002206 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002207 if (!AddTransportOffer(media_description_options.mid,
2208 media_description_options.transport_options,
2209 current_description, desc, ice_credentials)) {
2210 return false;
2211 }
2212 return true;
2213}
2214
2215bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2216 const MediaDescriptionOptions& media_description_options,
2217 const MediaSessionOptions& session_options,
2218 const ContentInfo* current_content,
2219 const SessionDescription* current_description,
2220 const RtpDataCodecs& rtp_data_codecs,
2221 StreamParamsVec* current_streams,
2222 SessionDescription* desc,
2223 IceCredentialsIterator* ice_credentials) const {
2224 std::unique_ptr<RtpDataContentDescription> data(
2225 new RtpDataContentDescription());
2226 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2227
2228 cricket::SecurePolicy sdes_policy =
2229 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2230 : secure();
2231 std::vector<std::string> crypto_suites;
2232 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2233 &crypto_suites);
2234 if (!CreateMediaContentOffer(media_description_options, session_options,
2235 rtp_data_codecs, sdes_policy,
2236 GetCryptos(current_content), crypto_suites,
2237 RtpHeaderExtensions(), ssrc_generator_,
2238 current_streams, data.get())) {
2239 return false;
2240 }
2241
2242 data->set_bandwidth(kDataMaxBandwidth);
2243 SetMediaProtocol(secure_transport, data.get());
2244 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002245 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002246 if (!AddTransportOffer(media_description_options.mid,
2247 media_description_options.transport_options,
2248 current_description, desc, ice_credentials)) {
2249 return false;
2250 }
2251 return true;
2252}
2253
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002254bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002255 const MediaDescriptionOptions& media_description_options,
2256 const MediaSessionOptions& session_options,
2257 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002258 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002259 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002260 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002261 SessionDescription* desc,
2262 IceCredentialsIterator* ice_credentials) const {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07002263 bool is_sctp =
2264 (session_options.data_channel_type == DCT_SCTP ||
2265 session_options.data_channel_type == DCT_DATA_CHANNEL_TRANSPORT_SCTP);
zhihuang1c378ed2017-08-17 14:10:50 -07002266 // If the DataChannel type is not specified, use the DataChannel type in
2267 // the current description.
2268 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002269 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002270 is_sctp = (current_content->media_description()->protocol() ==
2271 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002272 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002274 return AddSctpDataContentForOffer(
2275 media_description_options, session_options, current_content,
2276 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002277 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002278 return AddRtpDataContentForOffer(media_description_options, session_options,
2279 current_content, current_description,
2280 rtp_data_codecs, current_streams, desc,
2281 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002282 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002283}
2284
zhihuang1c378ed2017-08-17 14:10:50 -07002285// |audio_codecs| = set of all possible codecs that can be used, with correct
2286// payload type mappings
2287//
2288// |supported_audio_codecs| = set of codecs that are supported for the direction
2289// of this m= section
2290//
2291// acd->codecs() = set of previously negotiated codecs for this m= section
2292//
2293// The payload types should come from audio_codecs, but the order should come
2294// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2295// change existing codec priority, and that new codecs are added with the right
2296// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002297bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002298 const MediaDescriptionOptions& media_description_options,
2299 const MediaSessionOptions& session_options,
2300 const ContentInfo* offer_content,
2301 const SessionDescription* offer_description,
2302 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002303 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002304 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002305 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002307 SessionDescription* answer,
2308 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002309 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002310 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002311 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002312
Steve Anton1a9d3c32018-12-10 17:18:54 -08002313 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002314 media_description_options.mid, offer_description,
2315 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002316 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002317 if (!audio_transport) {
2318 return false;
2319 }
2320
zhihuang1c378ed2017-08-17 14:10:50 -07002321 // Pick codecs based on the requested communications direction in the offer
2322 // and the selected direction in the answer.
2323 // Note these will be filtered one final time in CreateMediaContentAnswer.
2324 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002325 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002326 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002327 AudioCodecs supported_audio_codecs =
2328 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2329
2330 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002331
2332 if (!media_description_options.codec_preferences.empty()) {
2333 filtered_codecs = MatchCodecPreference(
2334 media_description_options.codec_preferences, supported_audio_codecs);
2335 } else {
2336 // Add the codecs from current content if it exists and is not rejected nor
2337 // recycled.
2338 if (current_content && !current_content->rejected &&
2339 current_content->name == media_description_options.mid) {
2340 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2341 const AudioContentDescription* acd =
2342 current_content->media_description()->as_audio();
2343 for (const AudioCodec& codec : acd->codecs()) {
2344 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2345 nullptr)) {
2346 filtered_codecs.push_back(codec);
2347 }
zhihuang1c378ed2017-08-17 14:10:50 -07002348 }
2349 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002350 // Add other supported audio codecs.
2351 for (const AudioCodec& codec : supported_audio_codecs) {
2352 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2353 codec, nullptr) &&
2354 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2355 filtered_codecs, codec, nullptr)) {
2356 // We should use the local codec with local parameters and the codec id
2357 // would be correctly mapped in |NegotiateCodecs|.
2358 filtered_codecs.push_back(codec);
2359 }
zhihuang1c378ed2017-08-17 14:10:50 -07002360 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002361 }
2362
zhihuang1c378ed2017-08-17 14:10:50 -07002363 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2364 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002365 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002366 new AudioContentDescription());
2367 // Do not require or create SDES cryptos if DTLS is used.
2368 cricket::SecurePolicy sdes_policy =
2369 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002370 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2371 media_description_options, session_options,
2372 ssrc_generator_, current_streams,
2373 audio_answer.get())) {
2374 return false;
2375 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002376 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002377 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002378 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002379 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002380 enable_encrypted_rtp_header_extensions_, current_streams,
2381 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002382 return false; // Fails the session setup.
2383 }
2384
deadbeefb7892532017-02-22 19:35:18 -08002385 bool secure = bundle_transport ? bundle_transport->description.secure()
2386 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002387 bool rejected = media_description_options.stopped ||
2388 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002389 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2390 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002391 if (!AddTransportAnswer(media_description_options.mid,
2392 *(audio_transport.get()), answer)) {
2393 return false;
2394 }
2395
2396 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002397 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2398 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002399 }
2400
zhihuang1c378ed2017-08-17 14:10:50 -07002401 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002402 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002403 return true;
2404}
2405
2406bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002407 const MediaDescriptionOptions& media_description_options,
2408 const MediaSessionOptions& session_options,
2409 const ContentInfo* offer_content,
2410 const SessionDescription* offer_description,
2411 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002412 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002413 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002414 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002415 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002416 SessionDescription* answer,
2417 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002418 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002419 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002420 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002421
Steve Anton1a9d3c32018-12-10 17:18:54 -08002422 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002423 media_description_options.mid, offer_description,
2424 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002425 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002426 if (!video_transport) {
2427 return false;
2428 }
2429
zhihuang1c378ed2017-08-17 14:10:50 -07002430 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002431
2432 if (!media_description_options.codec_preferences.empty()) {
2433 filtered_codecs = MatchCodecPreference(
2434 media_description_options.codec_preferences, video_codecs_);
2435 } else {
2436 // Add the codecs from current content if it exists and is not rejected nor
2437 // recycled.
2438 if (current_content && !current_content->rejected &&
2439 current_content->name == media_description_options.mid) {
2440 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2441 const VideoContentDescription* vcd =
2442 current_content->media_description()->as_video();
2443 for (const VideoCodec& codec : vcd->codecs()) {
2444 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2445 nullptr)) {
2446 filtered_codecs.push_back(codec);
2447 }
zhihuang1c378ed2017-08-17 14:10:50 -07002448 }
2449 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002450 // Add other supported video codecs.
2451 for (const VideoCodec& codec : video_codecs_) {
2452 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2453 nullptr) &&
2454 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2455 nullptr)) {
2456 // We should use the local codec with local parameters and the codec id
2457 // would be correctly mapped in |NegotiateCodecs|.
2458 filtered_codecs.push_back(codec);
2459 }
zhihuang1c378ed2017-08-17 14:10:50 -07002460 }
2461 }
2462
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002463 if (session_options.raw_packetization_for_video) {
2464 for (VideoCodec& codec : filtered_codecs) {
2465 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2466 codec.packetization = kPacketizationParamRaw;
2467 }
2468 }
2469 }
2470
zhihuang1c378ed2017-08-17 14:10:50 -07002471 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2472 session_options.bundle_enabled;
2473
kwiberg31022942016-03-11 14:18:21 -08002474 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002475 new VideoContentDescription());
2476 // Do not require or create SDES cryptos if DTLS is used.
2477 cricket::SecurePolicy sdes_policy =
2478 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002479 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2480 media_description_options, session_options,
2481 ssrc_generator_, current_streams,
2482 video_answer.get())) {
2483 return false;
2484 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002485 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002486 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002487 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002488 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002489 enable_encrypted_rtp_header_extensions_, current_streams,
2490 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002491 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002492 }
deadbeefb7892532017-02-22 19:35:18 -08002493 bool secure = bundle_transport ? bundle_transport->description.secure()
2494 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002495 bool rejected = media_description_options.stopped ||
2496 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002497 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2498 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002499 if (!AddTransportAnswer(media_description_options.mid,
2500 *(video_transport.get()), answer)) {
2501 return false;
2502 }
2503
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002504 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002505 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002506 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002507 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2508 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002509 }
zhihuang1c378ed2017-08-17 14:10:50 -07002510 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002511 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002512 return true;
2513}
2514
2515bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002516 const MediaDescriptionOptions& media_description_options,
2517 const MediaSessionOptions& session_options,
2518 const ContentInfo* offer_content,
2519 const SessionDescription* offer_description,
2520 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002521 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002522 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002523 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002524 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002525 SessionDescription* answer,
2526 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002527 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002528 media_description_options.mid, offer_description,
2529 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002530 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002531 if (!data_transport) {
2532 return false;
2533 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002534
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002535 // Do not require or create SDES cryptos if DTLS is used.
2536 cricket::SecurePolicy sdes_policy =
2537 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002538 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2539 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002540 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002541 std::unique_ptr<MediaContentDescription> data_answer;
2542 if (offer_content->media_description()->as_sctp()) {
2543 // SCTP data content
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002544 data_answer = std::make_unique<SctpDataContentDescription>();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002545 const SctpDataContentDescription* offer_data_description =
2546 offer_content->media_description()->as_sctp();
2547 // Respond with the offerer's proto, whatever it is.
2548 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002549 // Respond with our max message size or the remote max messsage size,
2550 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002551 // 0 is treated specially - it means "I can accept any size". Since
2552 // we do not implement infinite size messages, reply with
2553 // kSctpSendBufferSize.
2554 if (offer_data_description->max_message_size() == 0) {
2555 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2556 } else {
2557 data_answer->as_sctp()->set_max_message_size(std::min(
2558 offer_data_description->max_message_size(), kSctpSendBufferSize));
2559 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002560 if (!CreateMediaContentAnswer(
2561 offer_data_description, media_description_options, session_options,
2562 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2563 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2564 current_streams, bundle_enabled, data_answer.get())) {
2565 return false; // Fails the session setup.
2566 }
2567 // Respond with sctpmap if the offer uses sctpmap.
2568 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2569 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2570 } else {
2571 // RTP offer
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002572 data_answer = std::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002573
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002574 const RtpDataContentDescription* offer_data_description =
2575 offer_content->media_description()->as_rtp_data();
2576 RTC_CHECK(offer_data_description);
2577 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2578 media_description_options, session_options,
2579 ssrc_generator_, current_streams,
2580 data_answer->as_rtp_data())) {
2581 return false;
2582 }
2583 if (!CreateMediaContentAnswer(
2584 offer_data_description, media_description_options, session_options,
2585 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2586 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2587 current_streams, bundle_enabled, data_answer.get())) {
2588 return false; // Fails the session setup.
2589 }
2590 }
Steve Anton46afbf92019-05-10 11:15:18 -07002591
deadbeefb7892532017-02-22 19:35:18 -08002592 bool secure = bundle_transport ? bundle_transport->description.secure()
2593 : data_transport->secure();
2594
zhihuang1c378ed2017-08-17 14:10:50 -07002595 bool rejected = session_options.data_channel_type == DCT_NONE ||
2596 media_description_options.stopped ||
2597 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002598 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2599 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002600 if (!AddTransportAnswer(media_description_options.mid,
2601 *(data_transport.get()), answer)) {
2602 return false;
2603 }
2604
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002605 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002606 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002607 } else {
2608 // RFC 3264
2609 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002610 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002611 }
zhihuang1c378ed2017-08-17 14:10:50 -07002612 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002613 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002614 return true;
2615}
2616
zhihuang1c378ed2017-08-17 14:10:50 -07002617void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2618 audio_sendrecv_codecs_.clear();
2619 all_audio_codecs_.clear();
2620 // Compute the audio codecs union.
2621 for (const AudioCodec& send : audio_send_codecs_) {
2622 all_audio_codecs_.push_back(send);
2623 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2624 send, nullptr)) {
2625 // It doesn't make sense to have an RTX codec we support sending but not
2626 // receiving.
2627 RTC_DCHECK(!IsRtxCodec(send));
2628 }
2629 }
2630 for (const AudioCodec& recv : audio_recv_codecs_) {
2631 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2632 recv, nullptr)) {
2633 all_audio_codecs_.push_back(recv);
2634 }
2635 }
2636 // Use NegotiateCodecs to merge our codec lists, since the operation is
2637 // essentially the same. Put send_codecs as the offered_codecs, which is the
2638 // order we'd like to follow. The reasoning is that encoding is usually more
2639 // expensive than decoding, and prioritizing a codec in the send list probably
2640 // means it's a codec we can handle efficiently.
2641 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002642 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002643}
2644
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002645bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002646 return (content && (content->type == MediaProtocolType::kRtp ||
2647 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002648}
2649
2650bool IsAudioContent(const ContentInfo* content) {
2651 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2652}
2653
2654bool IsVideoContent(const ContentInfo* content) {
2655 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2656}
2657
2658bool IsDataContent(const ContentInfo* content) {
2659 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2660}
2661
deadbeef0ed85b22016-02-23 17:24:52 -08002662const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2663 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002664 for (const ContentInfo& content : contents) {
2665 if (IsMediaContentOfType(&content, media_type)) {
2666 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667 }
2668 }
deadbeef0ed85b22016-02-23 17:24:52 -08002669 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670}
2671
2672const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2673 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2674}
2675
2676const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2677 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2678}
2679
2680const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2681 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2682}
2683
Steve Antonad7bffc2018-01-22 10:21:56 -08002684const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2685 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002686 if (sdesc == nullptr) {
2687 return nullptr;
2688 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689
2690 return GetFirstMediaContent(sdesc->contents(), media_type);
2691}
2692
2693const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2694 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2695}
2696
2697const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2698 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2699}
2700
2701const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2702 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2703}
2704
2705const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002706 const SessionDescription* sdesc,
2707 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002708 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002709 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710}
2711
2712const AudioContentDescription* GetFirstAudioContentDescription(
2713 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002714 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2715 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716}
2717
2718const VideoContentDescription* GetFirstVideoContentDescription(
2719 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002720 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2721 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722}
2723
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002724const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2725 const SessionDescription* sdesc) {
2726 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2727 return desc ? desc->as_rtp_data() : nullptr;
2728}
2729
2730const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2731 const SessionDescription* sdesc) {
2732 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2733 return desc ? desc->as_sctp() : nullptr;
2734}
2735
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002736//
2737// Non-const versions of the above functions.
2738//
2739
Steve Anton36b29d12017-10-30 09:57:42 -07002740ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002741 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002742 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002743 if (IsMediaContentOfType(&content, media_type)) {
2744 return &content;
2745 }
2746 }
2747 return nullptr;
2748}
2749
Steve Anton36b29d12017-10-30 09:57:42 -07002750ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002751 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2752}
2753
Steve Anton36b29d12017-10-30 09:57:42 -07002754ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002755 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2756}
2757
Steve Anton36b29d12017-10-30 09:57:42 -07002758ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002759 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2760}
2761
Steve Antonad7bffc2018-01-22 10:21:56 -08002762ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2763 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002764 if (sdesc == nullptr) {
2765 return nullptr;
2766 }
2767
Steve Anton36b29d12017-10-30 09:57:42 -07002768 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002769}
2770
2771ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2772 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2773}
2774
2775ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2776 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2777}
2778
2779ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2780 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2781}
2782
2783MediaContentDescription* GetFirstMediaContentDescription(
2784 SessionDescription* sdesc,
2785 MediaType media_type) {
2786 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002787 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002788}
2789
2790AudioContentDescription* GetFirstAudioContentDescription(
2791 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002792 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2793 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002794}
2795
2796VideoContentDescription* GetFirstVideoContentDescription(
2797 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002798 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2799 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002800}
2801
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002802RtpDataContentDescription* GetFirstRtpDataContentDescription(
2803 SessionDescription* sdesc) {
2804 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2805 return desc ? desc->as_rtp_data() : nullptr;
2806}
2807
2808SctpDataContentDescription* GetFirstSctpDataContentDescription(
2809 SessionDescription* sdesc) {
2810 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2811 return desc ? desc->as_sctp() : nullptr;
2812}
2813
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814} // namespace cricket