blob: ff9c17b27cd075bc589bcf7944565cae9ca316ee [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
deadbeef7af91dd2016-12-13 11:29:11 -0800664 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 return false;
666 }
667 return true;
668}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200669template <class C>
670static bool CreateMediaContentOffer(
671 const MediaDescriptionOptions& media_description_options,
672 const MediaSessionOptions& session_options,
673 const std::vector<C>& codecs,
674 const SecurePolicy& secure_policy,
675 const CryptoParamsVec* current_cryptos,
676 const std::vector<std::string>& crypto_suites,
677 const RtpHeaderExtensions& rtp_extensions,
678 UniqueRandomIdGenerator* ssrc_generator,
679 StreamParamsVec* current_streams,
680 MediaContentDescriptionImpl<C>* offer) {
681 offer->AddCodecs(codecs);
682 if (!AddStreamParams(media_description_options.sender_options,
683 session_options.rtcp_cname, ssrc_generator,
684 current_streams, offer)) {
685 return false;
686 }
687
688 return CreateContentOffer(media_description_options, session_options,
689 secure_policy, current_cryptos, crypto_suites,
690 rtp_extensions, ssrc_generator, current_streams,
691 offer);
692}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693
694template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000695static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800696 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000697 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800698 const int codec2_id) {
699 const C* codec1 = FindCodecById(codecs1, codec1_id);
700 const C* codec2 = FindCodecById(codecs2, codec2_id);
701 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000702}
703
704template <class C>
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200705static void NegotiatePacketization(const C& local_codec,
706 const C& remote_codec,
707 C* negotiated_codec) {}
708
709template <>
710void NegotiatePacketization(const VideoCodec& local_codec,
711 const VideoCodec& remote_codec,
712 VideoCodec* negotiated_codec) {
713 negotiated_codec->packetization =
714 VideoCodec::IntersectPacketization(local_codec, remote_codec);
715}
716
717template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718static void NegotiateCodecs(const std::vector<C>& local_codecs,
719 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200720 std::vector<C>* negotiated_codecs,
721 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800722 for (const C& ours : local_codecs) {
723 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700724 // Note that we intentionally only find one matching codec for each of our
725 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800726 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
727 C negotiated = ours;
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200728 NegotiatePacketization(ours, theirs, &negotiated);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800729 negotiated.IntersectFeedbackParams(theirs);
730 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800731 const auto apt_it =
732 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800733 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800734 RTC_DCHECK(apt_it != theirs.params.end());
735 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 }
Niels Möller039743e2018-10-23 10:07:25 +0200737 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800738 webrtc::H264::GenerateProfileLevelIdForAnswer(
739 ours.params, theirs.params, &negotiated.params);
740 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800741 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700742 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800743 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 }
745 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200746 if (keep_offer_order) {
747 // RFC3264: Although the answerer MAY list the formats in their desired
748 // order of preference, it is RECOMMENDED that unless there is a
749 // specific reason, the answerer list formats in the same relative order
750 // they were present in the offer.
751 // This can be skipped when the transceiver has any codec preferences.
752 std::unordered_map<int, int> payload_type_preferences;
753 int preference = static_cast<int>(offered_codecs.size() + 1);
754 for (const C& codec : offered_codecs) {
755 payload_type_preferences[codec.id] = preference--;
756 }
757 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
758 const C& b) {
759 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
760 });
deadbeef67cf2c12016-04-13 10:07:16 -0700761 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762}
763
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800764// Finds a codec in |codecs2| that matches |codec_to_match|, which is
765// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
766// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800768static bool FindMatchingCodec(const std::vector<C>& codecs1,
769 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 const C& codec_to_match,
771 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700772 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
773 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800774 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
775 return &codec == &codec_to_match;
776 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800777 for (const C& potential_match : codecs2) {
778 if (potential_match.Matches(codec_to_match)) {
779 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800780 int apt_value_1 = 0;
781 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800782 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
783 &apt_value_1) ||
784 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
785 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100786 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800787 continue;
788 }
789 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
790 apt_value_2)) {
791 continue;
792 }
793 }
794 if (found_codec) {
795 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 }
797 return true;
798 }
799 }
800 return false;
801}
802
zhihuang1c378ed2017-08-17 14:10:50 -0700803// Find the codec in |codec_list| that |rtx_codec| is associated with.
804template <class C>
805static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
806 const C& rtx_codec) {
807 std::string associated_pt_str;
808 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
809 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100810 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
811 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700812 return nullptr;
813 }
814
815 int associated_pt;
816 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100817 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
818 << " of RTX codec " << rtx_codec.name
819 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700820 return nullptr;
821 }
822
823 // Find the associated reference codec for the reference RTX codec.
824 const C* associated_codec = FindCodecById(codec_list, associated_pt);
825 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100826 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
827 << associated_pt << " for RTX codec " << rtx_codec.name
828 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700829 }
830 return associated_codec;
831}
832
833// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834// already exist in |offered_codecs| and ensure the payload types don't
835// collide.
836template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700837static void MergeCodecs(const std::vector<C>& reference_codecs,
838 std::vector<C>* offered_codecs,
839 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800841 for (const C& reference_codec : reference_codecs) {
842 if (!IsRtxCodec(reference_codec) &&
843 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
844 reference_codec, nullptr)) {
845 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 used_pltypes->FindAndSetIdUsed(&codec);
847 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 }
849 }
850
851 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852 for (const C& reference_codec : reference_codecs) {
853 if (IsRtxCodec(reference_codec) &&
854 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
855 reference_codec, nullptr)) {
856 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700857 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700858 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700859 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700860 continue;
861 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800862 // Find a codec in the offered list that matches the reference codec.
863 // Its payload type may be different than the reference codec.
864 C matching_codec;
865 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800866 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100867 RTC_LOG(LS_WARNING)
868 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800869 continue;
870 }
871
872 rtx_codec.params[kCodecParamAssociatedPayloadType] =
873 rtc::ToString(matching_codec.id);
874 used_pltypes->FindAndSetIdUsed(&rtx_codec);
875 offered_codecs->push_back(rtx_codec);
876 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 }
878}
879
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200880template <typename Codecs>
881static Codecs MatchCodecPreference(
882 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
883 const Codecs& codecs) {
884 Codecs filtered_codecs;
885 std::set<std::string> kept_codecs_ids;
886 bool want_rtx = false;
887
888 for (const auto& codec_preference : codec_preferences) {
889 auto found_codec = absl::c_find_if(
890 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
891 webrtc::RtpCodecParameters codec_parameters =
892 codec.ToCodecParameters();
893 return codec_parameters.name == codec_preference.name &&
894 codec_parameters.kind == codec_preference.kind &&
895 codec_parameters.num_channels ==
896 codec_preference.num_channels &&
897 codec_parameters.clock_rate == codec_preference.clock_rate &&
898 codec_parameters.parameters == codec_preference.parameters;
899 });
900
901 if (found_codec != codecs.end()) {
902 filtered_codecs.push_back(*found_codec);
903 kept_codecs_ids.insert(std::to_string(found_codec->id));
904 } else if (IsRtxCodec(codec_preference)) {
905 want_rtx = true;
906 }
907 }
908
909 if (want_rtx) {
910 for (const auto& codec : codecs) {
911 if (IsRtxCodec(codec)) {
912 const auto apt =
913 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
914 if (apt != codec.params.end() &&
915 kept_codecs_ids.count(apt->second) > 0) {
916 filtered_codecs.push_back(codec);
917 }
918 }
919 }
920 }
921
922 return filtered_codecs;
923}
924
zhihuang1c378ed2017-08-17 14:10:50 -0700925static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
926 const webrtc::RtpExtension& ext_to_match,
927 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800928 auto it = absl::c_find_if(
929 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
930 // We assume that all URIs are given in a canonical
931 // format.
932 return extension.uri == ext_to_match.uri &&
933 extension.encrypt == ext_to_match.encrypt;
934 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700935 if (it == extensions.end()) {
936 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700937 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700938 if (found_extension) {
939 *found_extension = *it;
940 }
941 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700942}
943
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700945 const webrtc::RtpExtension& ext_to_match,
946 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700947 // We assume that all URIs are given in a canonical format.
948 const webrtc::RtpExtension* found =
949 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
950 ext_to_match.uri);
951 if (!found) {
952 return false;
953 }
954 if (found_extension) {
955 *found_extension = *found;
956 }
957 return true;
958}
959
960static bool FindByUriWithEncryptionPreference(
961 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200962 const webrtc::RtpExtension& ext_to_match,
963 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700964 webrtc::RtpExtension* found_extension) {
965 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700966 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700968 if (extension.uri == ext_to_match.uri) {
969 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700970 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700971 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700972 }
973 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700975 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 }
977 }
jbauch5869f502017-06-29 12:31:36 -0700978 if (unencrypted_extension) {
979 if (found_extension) {
980 *found_extension = *unencrypted_extension;
981 }
982 return true;
983 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 return false;
985}
986
zhihuang1c378ed2017-08-17 14:10:50 -0700987// Adds all extensions from |reference_extensions| to |offered_extensions| that
988// don't already exist in |offered_extensions| and ensure the IDs don't
989// collide. If an extension is added, it's also added to |regular_extensions| or
990// |encrypted_extensions|, and if the extension is in |regular_extensions| or
991// |encrypted_extensions|, its ID is marked as used in |used_ids|.
992// |offered_extensions| is for either audio or video while |regular_extensions|
993// and |encrypted_extensions| are used for both audio and video. There could be
994// overlap between audio extensions and video extensions.
995static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
996 RtpHeaderExtensions* offered_extensions,
997 RtpHeaderExtensions* regular_extensions,
998 RtpHeaderExtensions* encrypted_extensions,
999 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001000 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001001 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1002 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001003 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001004 if (reference_extension.encrypt) {
1005 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1006 &existing)) {
1007 offered_extensions->push_back(existing);
1008 } else {
1009 used_ids->FindAndSetIdUsed(&reference_extension);
1010 encrypted_extensions->push_back(reference_extension);
1011 offered_extensions->push_back(reference_extension);
1012 }
olka3c747662017-08-17 06:50:32 -07001013 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001014 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1015 &existing)) {
1016 offered_extensions->push_back(existing);
1017 } else {
1018 used_ids->FindAndSetIdUsed(&reference_extension);
1019 regular_extensions->push_back(reference_extension);
1020 offered_extensions->push_back(reference_extension);
1021 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001022 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 }
1024 }
1025}
1026
jbauch5869f502017-06-29 12:31:36 -07001027static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1028 RtpHeaderExtensions* all_extensions,
1029 UsedRtpHeaderExtensionIds* used_ids) {
1030 RtpHeaderExtensions encrypted_extensions;
1031 for (const webrtc::RtpExtension& extension : *extensions) {
1032 webrtc::RtpExtension existing;
1033 // Don't add encrypted extensions again that were already included in a
1034 // previous offer or regular extensions that are also included as encrypted
1035 // extensions.
1036 if (extension.encrypt ||
1037 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1038 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001039 &existing) &&
1040 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001041 continue;
1042 }
1043
1044 if (FindByUri(*all_extensions, extension, &existing)) {
1045 encrypted_extensions.push_back(existing);
1046 } else {
1047 webrtc::RtpExtension encrypted(extension);
1048 encrypted.encrypt = true;
1049 used_ids->FindAndSetIdUsed(&encrypted);
1050 all_extensions->push_back(encrypted);
1051 encrypted_extensions.push_back(encrypted);
1052 }
1053 }
1054 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001055 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001056}
1057
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058static void NegotiateRtpHeaderExtensions(
1059 const RtpHeaderExtensions& local_extensions,
1060 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001061 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001062 RtpHeaderExtensions* negotiated_extensions) {
1063 // TransportSequenceNumberV2 is not offered by default. The special logic for
1064 // the TransportSequenceNumber extensions works as follows:
1065 // Offer Answer
1066 // V1 V1 if in local_extensions.
1067 // V1 and V2 V2 regardless of local_extensions.
1068 // V2 V2 regardless of local_extensions.
1069 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1070 webrtc::RtpExtension::FindHeaderExtensionByUri(
1071 offered_extensions,
1072 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1073
Steve Anton3a66edf2018-09-10 12:57:37 -07001074 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001075 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001076 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001077 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001078 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001079 if (transport_sequence_number_v2_offer &&
1080 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1081 // Don't respond to
1082 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1083 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001084 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001085 continue;
1086 } else {
1087 // We respond with their RTP header extension id.
1088 negotiated_extensions->push_back(theirs);
1089 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 }
1091 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001092
1093 if (transport_sequence_number_v2_offer) {
1094 // Respond that we support kTransportSequenceNumberV2Uri.
1095 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1096 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001097}
1098
1099static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001100 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1101 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001102 return absl::EqualsIgnoreCase(
1103 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001104 }),
1105 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106}
1107
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001108template <class C>
1109static bool SetCodecsInAnswer(
1110 const MediaContentDescriptionImpl<C>* offer,
1111 const std::vector<C>& local_codecs,
1112 const MediaDescriptionOptions& media_description_options,
1113 const MediaSessionOptions& session_options,
1114 UniqueRandomIdGenerator* ssrc_generator,
1115 StreamParamsVec* current_streams,
1116 MediaContentDescriptionImpl<C>* answer) {
1117 std::vector<C> negotiated_codecs;
1118 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1119 media_description_options.codec_preferences.empty());
1120 answer->AddCodecs(negotiated_codecs);
1121 answer->set_protocol(offer->protocol());
1122 if (!AddStreamParams(media_description_options.sender_options,
1123 session_options.rtcp_cname, ssrc_generator,
1124 current_streams, answer)) {
1125 return false; // Something went seriously wrong.
1126 }
1127 return true;
1128}
1129
zhihuang1c378ed2017-08-17 14:10:50 -07001130// Create a media content to be answered for the given |sender_options|
1131// according to the given session_options.rtcp_mux, session_options.streams,
1132// codecs, crypto, and current_streams. If we don't currently have crypto (in
1133// current_cryptos) and it is enabled (in secure_policy), crypto is created
1134// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1135// negotiated with the offer. If the negotiation fails, this method returns
1136// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001138 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001139 const MediaDescriptionOptions& media_description_options,
1140 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001141 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001142 const CryptoParamsVec* current_cryptos,
1143 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001144 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001145 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001146 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001148 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001149 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001151 NegotiateRtpHeaderExtensions(
1152 local_rtp_extenstions, offer->rtp_header_extensions(),
1153 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001154 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1155
zhihuang1c378ed2017-08-17 14:10:50 -07001156 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001157 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1158 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1159 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160
Sebastian Janssone1795f42019-07-24 11:38:03 +02001161 answer->set_remote_estimate(offer->remote_estimate());
1162
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163 if (sdes_policy != SEC_DISABLED) {
1164 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001165 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1166 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167 if (current_cryptos) {
1168 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1169 }
1170 answer->AddCrypto(crypto);
1171 }
1172 }
1173
deadbeef7af91dd2016-12-13 11:29:11 -08001174 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 return false;
1176 }
1177
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001178 AddSimulcastToMediaDescription(media_description_options, answer);
1179
Steve Anton4e70a722017-11-28 14:57:10 -08001180 answer->set_direction(NegotiateRtpTransceiverDirection(
1181 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182 return true;
1183}
1184
1185static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001186 const std::string& protocol,
1187 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001188 // Since not all applications serialize and deserialize the media protocol,
1189 // we will have to accept |protocol| to be empty.
1190 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 return true;
1192 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001193
zhihuangcf5b37c2016-05-05 11:44:35 -07001194 if (type == MEDIA_TYPE_DATA) {
1195 // Check for SCTP, but also for RTP for RTP-based data channels.
1196 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1197 if (secure_transport) {
1198 // Most likely scenarios first.
1199 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1200 IsPlainRtp(protocol);
1201 } else {
1202 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1203 }
1204 }
1205
1206 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1207 // JSEP specifies.
1208 if (secure_transport) {
1209 // Most likely scenarios first.
1210 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1211 } else {
1212 return IsPlainRtp(protocol);
1213 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214}
1215
1216static void SetMediaProtocol(bool secure_transport,
1217 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001218 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001220 else if (secure_transport)
1221 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 else
1223 desc->set_protocol(kMediaProtocolAvpf);
1224}
1225
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001226// Gets the TransportInfo of the given |content_name| from the
1227// |current_description|. If doesn't exist, returns a new one.
1228static const TransportDescription* GetTransportDescription(
1229 const std::string& content_name,
1230 const SessionDescription* current_description) {
1231 const TransportDescription* desc = NULL;
1232 if (current_description) {
1233 const TransportInfo* info =
1234 current_description->GetTransportInfoByName(content_name);
1235 if (info) {
1236 desc = &info->description;
1237 }
1238 }
1239 return desc;
1240}
1241
1242// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001243static bool IsDtlsActive(const ContentInfo* content,
1244 const SessionDescription* current_description) {
1245 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001246 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001247 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001248
zhihuang1c378ed2017-08-17 14:10:50 -07001249 size_t msection_index = content - &current_description->contents()[0];
1250
1251 if (current_description->transport_infos().size() <= msection_index) {
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 return current_description->transport_infos()[msection_index]
1256 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001257}
1258
Steve Anton8ffb9c32017-08-31 15:45:38 -07001259void MediaDescriptionOptions::AddAudioSender(
1260 const std::string& track_id,
1261 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001262 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001263 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001264}
1265
Steve Anton8ffb9c32017-08-31 15:45:38 -07001266void MediaDescriptionOptions::AddVideoSender(
1267 const std::string& track_id,
1268 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001269 const std::vector<RidDescription>& rids,
1270 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001271 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001272 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001273 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1274 << "RIDs are the compliant way to indicate simulcast.";
1275 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1276 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1277 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001278}
1279
zhihuang1c378ed2017-08-17 14:10:50 -07001280void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1281 const std::string& stream_id) {
1282 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001283 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1284 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001285 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286}
1287
Steve Anton8ffb9c32017-08-31 15:45:38 -07001288void MediaDescriptionOptions::AddSenderInternal(
1289 const std::string& track_id,
1290 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001291 const std::vector<RidDescription>& rids,
1292 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001293 int num_sim_layers) {
1294 // TODO(steveanton): Support any number of stream ids.
1295 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001296 SenderOptions options;
1297 options.track_id = track_id;
1298 options.stream_ids = stream_ids;
1299 options.simulcast_layers = simulcast_layers;
1300 options.rids = rids;
1301 options.num_sim_layers = num_sim_layers;
1302 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303}
1304
zhihuang1c378ed2017-08-17 14:10:50 -07001305bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001306 return absl::c_any_of(
1307 media_description_options,
1308 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001309}
1310
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001312 const TransportDescriptionFactory* transport_desc_factory,
1313 rtc::UniqueRandomIdGenerator* ssrc_generator)
1314 : ssrc_generator_(ssrc_generator),
1315 transport_desc_factory_(transport_desc_factory) {
1316 RTC_DCHECK(ssrc_generator_);
1317}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318
1319MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1320 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001321 const TransportDescriptionFactory* transport_desc_factory,
1322 rtc::UniqueRandomIdGenerator* ssrc_generator)
1323 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001324 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1325 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001327 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001329 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001330 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001331}
1332
ossudedfd282016-06-14 07:12:39 -07001333const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1334 const {
ossu075af922016-06-14 03:29:38 -07001335 return audio_sendrecv_codecs_;
1336}
1337
1338const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1339 return audio_send_codecs_;
1340}
1341
1342const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1343 return audio_recv_codecs_;
1344}
1345
1346void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001347 const AudioCodecs& send_codecs,
1348 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001349 audio_send_codecs_ = send_codecs;
1350 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001351 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352}
1353
Amit Hilbuch77938e62018-12-21 09:23:38 -08001354static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1355 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001356
1357 rtc::UniqueNumberGenerator<int> unique_id_generator;
1358 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1359 for (const webrtc::RtpExtension& extension : *extensions) {
1360 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1361 RTC_DCHECK(collision_free);
1362 }
1363
Amit Hilbuch77938e62018-12-21 09:23:38 -08001364 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001365 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1366 unique_id_generator()));
1367 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1368 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001369 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001370 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001371}
1372
1373RtpHeaderExtensions
1374MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1375 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1376 if (is_unified_plan_) {
1377 AddUnifiedPlanExtensions(&extensions);
1378 }
1379
1380 return extensions;
1381}
1382
1383RtpHeaderExtensions
1384MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1385 RtpHeaderExtensions extensions = video_rtp_extensions_;
1386 if (is_unified_plan_) {
1387 AddUnifiedPlanExtensions(&extensions);
1388 }
1389
1390 return extensions;
1391}
1392
Steve Anton6fe1fba2018-12-11 10:15:23 -08001393std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001394 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001395 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001396 // Must have options for each existing section.
1397 if (current_description) {
1398 RTC_DCHECK_LE(current_description->contents().size(),
1399 session_options.media_description_options.size());
1400 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001401
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001402 IceCredentialsIterator ice_credentials(
1403 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001404
1405 std::vector<const ContentInfo*> current_active_contents;
1406 if (current_description) {
1407 current_active_contents =
1408 GetActiveContents(*current_description, session_options);
1409 }
1410
1411 StreamParamsVec current_streams =
1412 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001413
zhihuang1c378ed2017-08-17 14:10:50 -07001414 AudioCodecs offer_audio_codecs;
1415 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001416 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001417 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001418 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001419
zhihuang1c378ed2017-08-17 14:10:50 -07001420 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001421 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001422 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001423 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001424 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001425 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426
1427 RtpHeaderExtensions audio_rtp_extensions;
1428 RtpHeaderExtensions video_rtp_extensions;
Johannes Kron746dd0d2019-06-20 15:37:52 +02001429 GetRtpHdrExtsToOffer(current_active_contents,
1430 session_options.offer_extmap_allow_mixed,
1431 &audio_rtp_extensions, &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001433 auto offer = std::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001434
zhihuang1c378ed2017-08-17 14:10:50 -07001435 // Iterate through the media description options, matching with existing media
1436 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001437 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001438 for (const MediaDescriptionOptions& media_description_options :
1439 session_options.media_description_options) {
1440 const ContentInfo* current_content = nullptr;
1441 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001442 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001443 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001444 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001445 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001446 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001447 media_description_options.type));
1448 }
1449 switch (media_description_options.type) {
1450 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001451 if (!AddAudioContentForOffer(
1452 media_description_options, session_options, current_content,
1453 current_description, audio_rtp_extensions, offer_audio_codecs,
1454 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001455 return nullptr;
1456 }
1457 break;
1458 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001459 if (!AddVideoContentForOffer(
1460 media_description_options, session_options, current_content,
1461 current_description, video_rtp_extensions, offer_video_codecs,
1462 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001463 return nullptr;
1464 }
1465 break;
1466 case MEDIA_TYPE_DATA:
1467 if (!AddDataContentForOffer(media_description_options, session_options,
1468 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001469 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001470 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001471 return nullptr;
1472 }
1473 break;
1474 default:
1475 RTC_NOTREACHED();
1476 }
1477 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001478 }
1479
1480 // Bundle the contents together, if we've been asked to do so, and update any
1481 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001482 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001483 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001484 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001485 if (content.rejected) {
1486 continue;
1487 }
zhihuang1c378ed2017-08-17 14:10:50 -07001488 // TODO(deadbeef): There are conditions that make bundling two media
1489 // descriptions together illegal. For example, they use the same payload
1490 // type to represent different codecs, or same IDs for different header
1491 // extensions. We need to detect this and not try to bundle those media
1492 // descriptions together.
1493 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 }
Steve Anton2bed3972019-01-04 17:04:30 -08001495 if (!offer_bundle.content_names().empty()) {
1496 offer->AddGroup(offer_bundle);
1497 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1498 RTC_LOG(LS_ERROR)
1499 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1500 return nullptr;
1501 }
1502 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1503 RTC_LOG(LS_ERROR)
1504 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1505 return nullptr;
1506 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 }
1508 }
Steve Antone831b8c2018-02-01 12:22:16 -08001509
1510 // The following determines how to signal MSIDs to ensure compatibility with
1511 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001512 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001513 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1514 // Plan answerers will look at a=msid and Plan B answerers will look at the
1515 // a=ssrc MSID line.
1516 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1517 cricket::kMsidSignalingSsrcAttribute);
1518 } else {
1519 // Plan B always signals MSID using a=ssrc lines.
1520 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1521 }
1522
Johannes Kron89f874e2018-11-12 10:25:48 +01001523 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1524
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001525 if (session_options.media_transport_settings.has_value()) {
1526 offer->AddMediaTransportSetting(
1527 session_options.media_transport_settings->transport_name,
1528 session_options.media_transport_settings->transport_setting);
1529 }
1530
Steve Anton6fe1fba2018-12-11 10:15:23 -08001531 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001532}
1533
Steve Anton6fe1fba2018-12-11 10:15:23 -08001534std::unique_ptr<SessionDescription>
1535MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001536 const SessionDescription* offer,
1537 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001539 if (!offer) {
1540 return nullptr;
1541 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001542
Steve Anton5c72e712018-12-10 14:25:30 -08001543 // Must have options for exactly as many sections as in the offer.
1544 RTC_DCHECK_EQ(offer->contents().size(),
1545 session_options.media_description_options.size());
1546
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001547 IceCredentialsIterator ice_credentials(
1548 session_options.pooled_ice_credentials);
1549
Steve Anton5c72e712018-12-10 14:25:30 -08001550 std::vector<const ContentInfo*> current_active_contents;
1551 if (current_description) {
1552 current_active_contents =
1553 GetActiveContents(*current_description, session_options);
1554 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001555
Steve Anton5c72e712018-12-10 14:25:30 -08001556 StreamParamsVec current_streams =
1557 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001558
zhihuang1c378ed2017-08-17 14:10:50 -07001559 // Get list of all possible codecs that respects existing payload type
1560 // mappings and uses a single payload type space.
1561 //
1562 // Note that these lists may be further filtered for each m= section; this
1563 // step is done just to establish the payload type mappings shared by all
1564 // sections.
1565 AudioCodecs answer_audio_codecs;
1566 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001567 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001568 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001569 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001570
1571 if (!session_options.vad_enabled) {
1572 // If application doesn't want CN codecs in answer.
1573 StripCNCodecs(&answer_audio_codecs);
1574 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001575 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001576 session_options.data_channel_type == DCT_SCTP);
1577
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001578 auto answer = std::make_unique<SessionDescription>();
Steve Anton5c72e712018-12-10 14:25:30 -08001579
1580 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1581 // group in the answer with the appropriate content names.
1582 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1583 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1584 // Transport info shared by the bundle group.
1585 std::unique_ptr<TransportInfo> bundle_transport;
1586
1587 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1588
zhihuang1c378ed2017-08-17 14:10:50 -07001589 // Iterate through the media description options, matching with existing
1590 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001591 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001592 for (const MediaDescriptionOptions& media_description_options :
1593 session_options.media_description_options) {
1594 const ContentInfo* offer_content = &offer->contents()[msection_index];
1595 // Media types and MIDs must match between the remote offer and the
1596 // MediaDescriptionOptions.
1597 RTC_DCHECK(
1598 IsMediaContentOfType(offer_content, media_description_options.type));
1599 RTC_DCHECK(media_description_options.mid == offer_content->name);
1600 const ContentInfo* current_content = nullptr;
1601 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001602 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001603 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001604 }
zhihuang1c378ed2017-08-17 14:10:50 -07001605 switch (media_description_options.type) {
1606 case MEDIA_TYPE_AUDIO:
1607 if (!AddAudioContentForAnswer(
1608 media_description_options, session_options, offer_content,
1609 offer, current_content, current_description,
1610 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001611 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001612 return nullptr;
1613 }
1614 break;
1615 case MEDIA_TYPE_VIDEO:
1616 if (!AddVideoContentForAnswer(
1617 media_description_options, session_options, offer_content,
1618 offer, current_content, current_description,
1619 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001620 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001621 return nullptr;
1622 }
1623 break;
1624 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001625 if (!AddDataContentForAnswer(
1626 media_description_options, session_options, offer_content,
1627 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001628 bundle_transport.get(), answer_rtp_data_codecs,
1629 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001630 return nullptr;
1631 }
1632 break;
1633 default:
1634 RTC_NOTREACHED();
1635 }
1636 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001637 // See if we can add the newly generated m= section to the BUNDLE group in
1638 // the answer.
1639 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001640 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001641 offer_bundle->HasContentName(added.name)) {
1642 answer_bundle.AddContentName(added.name);
1643 bundle_transport.reset(
1644 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646 }
1647
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001648 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1649 // it's empty. RFC5888 says:
1650 //
1651 // A SIP entity that receives an offer that contains an "a=group" line
1652 // with semantics that are understood MUST return an answer that
1653 // contains an "a=group" line with the same semantics.
1654 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001655 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001656 }
deadbeefb7892532017-02-22 19:35:18 -08001657
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001658 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001659 // Share the same ICE credentials and crypto params across all contents,
1660 // as BUNDLE requires.
1661 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001662 RTC_LOG(LS_ERROR)
1663 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001664 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001665 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666
deadbeefb7892532017-02-22 19:35:18 -08001667 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001668 RTC_LOG(LS_ERROR)
1669 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001670 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671 }
1672 }
1673
Steve Antone831b8c2018-02-01 12:22:16 -08001674 // The following determines how to signal MSIDs to ensure compatibility with
1675 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001676 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001677 // Unified Plan needs to look at what the offer included to find the most
1678 // compatible answer.
1679 if (offer->msid_signaling() == 0) {
1680 // We end up here in one of three cases:
1681 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1682 // matter what we pick here.
1683 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1684 // it also doesn't matter what we pick here.
1685 // 3. Media that's either sendonly or inactive from the remote endpoint.
1686 // We don't have any information to say whether the endpoint is Plan B
1687 // or Unified Plan, so be conservative and send both.
1688 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1689 cricket::kMsidSignalingSsrcAttribute);
1690 } else if (offer->msid_signaling() ==
1691 (cricket::kMsidSignalingMediaSection |
1692 cricket::kMsidSignalingSsrcAttribute)) {
1693 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1694 // probably talking to a Unified Plan endpoint so respond with just
1695 // a=msid.
1696 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1697 } else {
1698 // Otherwise, it's clear which method the offerer is using so repeat that
1699 // back to them.
1700 answer->set_msid_signaling(offer->msid_signaling());
1701 }
1702 } else {
1703 // Plan B always signals MSID using a=ssrc lines.
1704 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1705 }
1706
Steve Anton6fe1fba2018-12-11 10:15:23 -08001707 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001708}
1709
ossu075af922016-06-14 03:29:38 -07001710const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1711 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001712 switch (direction) {
1713 // If stream is inactive - generate list as if sendrecv.
1714 case RtpTransceiverDirection::kSendRecv:
1715 case RtpTransceiverDirection::kInactive:
1716 return audio_sendrecv_codecs_;
1717 case RtpTransceiverDirection::kSendOnly:
1718 return audio_send_codecs_;
1719 case RtpTransceiverDirection::kRecvOnly:
1720 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001721 }
Steve Anton1d03a752017-11-27 14:30:09 -08001722 RTC_NOTREACHED();
1723 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001724}
1725
1726const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1727 const RtpTransceiverDirection& offer,
1728 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001729 switch (answer) {
1730 // For inactive and sendrecv answers, generate lists as if we were to accept
1731 // the offer's direction. See RFC 3264 Section 6.1.
1732 case RtpTransceiverDirection::kSendRecv:
1733 case RtpTransceiverDirection::kInactive:
1734 return GetAudioCodecsForOffer(
1735 webrtc::RtpTransceiverDirectionReversed(offer));
1736 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001737 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001738 case RtpTransceiverDirection::kRecvOnly:
1739 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001740 }
Steve Anton1d03a752017-11-27 14:30:09 -08001741 RTC_NOTREACHED();
1742 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001743}
1744
Steve Anton5c72e712018-12-10 14:25:30 -08001745void MergeCodecsFromDescription(
1746 const std::vector<const ContentInfo*>& current_active_contents,
1747 AudioCodecs* audio_codecs,
1748 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001749 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001750 UsedPayloadTypes* used_pltypes) {
1751 for (const ContentInfo* content : current_active_contents) {
1752 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001753 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001754 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001755 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001756 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001757 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001758 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001759 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001760 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001761 const RtpDataContentDescription* data =
1762 content->media_description()->as_rtp_data();
1763 if (data) {
1764 // Only relevant for RTP datachannels
1765 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1766 used_pltypes);
1767 }
zhihuang1c378ed2017-08-17 14:10:50 -07001768 }
1769 }
1770}
1771
1772// Getting codecs for an offer involves these steps:
1773//
1774// 1. Construct payload type -> codec mappings for current description.
1775// 2. Add any reference codecs that weren't already present
1776// 3. For each individual media description (m= section), filter codecs based
1777// on the directional attribute (happens in another method).
1778void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001779 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001780 AudioCodecs* audio_codecs,
1781 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001782 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001783 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001784 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1785 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001786 UsedPayloadTypes used_pltypes;
1787 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001788 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789
Steve Anton5c72e712018-12-10 14:25:30 -08001790 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001791 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1792 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001793 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001794}
1795
1796// Getting codecs for an answer involves these steps:
1797//
1798// 1. Construct payload type -> codec mappings for current description.
1799// 2. Add any codecs from the offer that weren't already present.
1800// 3. Add any remaining codecs that weren't already present.
1801// 4. For each individual media description (m= section), filter codecs based
1802// on the directional attribute (happens in another method).
1803void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001804 const std::vector<const ContentInfo*>& current_active_contents,
1805 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001806 AudioCodecs* audio_codecs,
1807 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001808 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001809 // First - get all codecs from the current description if the media type
1810 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1811 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001812 UsedPayloadTypes used_pltypes;
1813 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001814 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001815
1816 // Second - filter out codecs that we don't support at all and should ignore.
1817 AudioCodecs filtered_offered_audio_codecs;
1818 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001819 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001820 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001821 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1822 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001823 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001824 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1825 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1826 filtered_offered_audio_codecs,
1827 offered_audio_codec, nullptr) &&
1828 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1829 offered_audio_codec, nullptr)) {
1830 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1831 }
1832 }
1833 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1834 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001835 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001836 for (const VideoCodec& offered_video_codec : video->codecs()) {
1837 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1838 filtered_offered_video_codecs,
1839 offered_video_codec, nullptr) &&
1840 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1841 offered_video_codec, nullptr)) {
1842 filtered_offered_video_codecs.push_back(offered_video_codec);
1843 }
1844 }
1845 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001846 const RtpDataContentDescription* data =
1847 content.media_description()->as_rtp_data();
1848 if (data) {
1849 // RTP data. This part is inactive for SCTP data.
1850 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1851 if (!FindMatchingCodec<RtpDataCodec>(
1852 data->codecs(), filtered_offered_rtp_data_codecs,
1853 offered_rtp_data_codec, nullptr) &&
1854 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1855 offered_rtp_data_codec,
1856 nullptr)) {
1857 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1858 }
zhihuang1c378ed2017-08-17 14:10:50 -07001859 }
1860 }
1861 }
1862 }
1863
Steve Anton5c72e712018-12-10 14:25:30 -08001864 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001865 // |remote_offer|.
1866 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1867 &used_pltypes);
1868 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1869 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001870 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001871 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001872}
1873
1874void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001875 const std::vector<const ContentInfo*>& current_active_contents,
Johannes Kron746dd0d2019-06-20 15:37:52 +02001876 bool extmap_allow_mixed,
zhihuang1c378ed2017-08-17 14:10:50 -07001877 RtpHeaderExtensions* offer_audio_extensions,
1878 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001879 // All header extensions allocated from the same range to avoid potential
1880 // issues when using BUNDLE.
Johannes Kron746dd0d2019-06-20 15:37:52 +02001881
1882 // Strictly speaking the SDP attribute extmap_allow_mixed signals that the
1883 // receiver supports an RTP stream where one- and two-byte RTP header
1884 // extensions are mixed. For backwards compatibility reasons it's used in
1885 // WebRTC to signal that two-byte RTP header extensions are supported.
1886 UsedRtpHeaderExtensionIds used_ids(
1887 extmap_allow_mixed ? UsedRtpHeaderExtensionIds::IdDomain::kTwoByteAllowed
1888 : UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly);
jbauch5869f502017-06-29 12:31:36 -07001889 RtpHeaderExtensions all_regular_extensions;
1890 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891
1892 // First - get all extensions from the current description if the media type
1893 // is used.
1894 // Add them to |used_ids| so the local ids are not reused if a new media
1895 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001896 for (const ContentInfo* content : current_active_contents) {
1897 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1898 const AudioContentDescription* audio =
1899 content->media_description()->as_audio();
1900 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1901 &all_regular_extensions, &all_encrypted_extensions,
1902 &used_ids);
1903 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1904 const VideoContentDescription* video =
1905 content->media_description()->as_video();
1906 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1907 &all_regular_extensions, &all_encrypted_extensions,
1908 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909 }
1910 }
1911
Steve Anton5c72e712018-12-10 14:25:30 -08001912 // Add our default RTP header extensions that are not in the current
1913 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001914 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1915 &all_regular_extensions, &all_encrypted_extensions,
1916 &used_ids);
1917 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1918 &all_regular_extensions, &all_encrypted_extensions,
1919 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001920
jbauch5869f502017-06-29 12:31:36 -07001921 // TODO(jbauch): Support adding encrypted header extensions to existing
1922 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001923 if (enable_encrypted_rtp_header_extensions_ &&
1924 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001925 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1926 &all_encrypted_extensions, &used_ids);
1927 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1928 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001929 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930}
1931
1932bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001933 const std::string& content_name,
1934 const TransportOptions& transport_options,
1935 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001936 SessionDescription* offer_desc,
1937 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001939 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 const TransportDescription* current_tdesc =
1941 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001942 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001943 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1944 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001945 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001946 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1947 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948 }
Steve Anton06817cd2018-12-18 15:55:30 -08001949 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1950 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951}
1952
Steve Anton1a9d3c32018-12-10 17:18:54 -08001953std::unique_ptr<TransportDescription>
1954MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955 const std::string& content_name,
1956 const SessionDescription* offer_desc,
1957 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001958 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001959 bool require_transport_attributes,
1960 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 if (!transport_desc_factory_)
1962 return NULL;
1963 const TransportDescription* offer_tdesc =
1964 GetTransportDescription(content_name, offer_desc);
1965 const TransportDescription* current_tdesc =
1966 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001967 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1968 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001969 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001970}
1971
1972bool MediaSessionDescriptionFactory::AddTransportAnswer(
1973 const std::string& content_name,
1974 const TransportDescription& transport_desc,
1975 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001976 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 return true;
1978}
1979
zhihuang1c378ed2017-08-17 14:10:50 -07001980// |audio_codecs| = set of all possible codecs that can be used, with correct
1981// payload type mappings
1982//
1983// |supported_audio_codecs| = set of codecs that are supported for the direction
1984// of this m= section
1985//
1986// acd->codecs() = set of previously negotiated codecs for this m= section
1987//
1988// The payload types should come from audio_codecs, but the order should come
1989// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1990// change existing codec priority, and that new codecs are added with the right
1991// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001992bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001993 const MediaDescriptionOptions& media_description_options,
1994 const MediaSessionOptions& session_options,
1995 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001996 const SessionDescription* current_description,
1997 const RtpHeaderExtensions& audio_rtp_extensions,
1998 const AudioCodecs& audio_codecs,
1999 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002000 SessionDescription* desc,
2001 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002002 // Filter audio_codecs (which includes all codecs, with correctly remapped
2003 // payload types) based on transceiver direction.
2004 const AudioCodecs& supported_audio_codecs =
2005 GetAudioCodecsForOffer(media_description_options.direction);
2006
2007 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002008
2009 if (!media_description_options.codec_preferences.empty()) {
2010 // Add the codecs from the current transceiver's codec preferences.
2011 // They override any existing codecs from previous negotiations.
2012 filtered_codecs = MatchCodecPreference(
2013 media_description_options.codec_preferences, supported_audio_codecs);
2014 } else {
2015 // Add the codecs from current content if it exists and is not rejected nor
2016 // recycled.
2017 if (current_content && !current_content->rejected &&
2018 current_content->name == media_description_options.mid) {
2019 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2020 const AudioContentDescription* acd =
2021 current_content->media_description()->as_audio();
2022 for (const AudioCodec& codec : acd->codecs()) {
2023 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2024 nullptr)) {
2025 filtered_codecs.push_back(codec);
2026 }
zhihuang1c378ed2017-08-17 14:10:50 -07002027 }
2028 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002029 // Add other supported audio codecs.
2030 AudioCodec found_codec;
2031 for (const AudioCodec& codec : supported_audio_codecs) {
2032 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2033 codec, &found_codec) &&
2034 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2035 filtered_codecs, codec, nullptr)) {
2036 // Use the |found_codec| from |audio_codecs| because it has the
2037 // correctly mapped payload type.
2038 filtered_codecs.push_back(found_codec);
2039 }
zhihuang1c378ed2017-08-17 14:10:50 -07002040 }
2041 }
deadbeef44f08192015-12-15 16:20:09 -08002042
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002043 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002044 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2045 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002046
kwiberg31022942016-03-11 14:18:21 -08002047 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002048 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002049 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2050 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002051 if (!CreateMediaContentOffer(media_description_options, session_options,
2052 filtered_codecs, sdes_policy,
2053 GetCryptos(current_content), crypto_suites,
2054 audio_rtp_extensions, ssrc_generator_,
2055 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002056 return false;
2057 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002058
2059 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2060 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002061
Steve Anton4e70a722017-11-28 14:57:10 -08002062 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002063
Steve Anton5adfafd2017-12-20 16:34:00 -08002064 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002065 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002066 if (!AddTransportOffer(media_description_options.mid,
2067 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002068 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002069 return false;
2070 }
2071
2072 return true;
2073}
2074
2075bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002076 const MediaDescriptionOptions& media_description_options,
2077 const MediaSessionOptions& session_options,
2078 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002079 const SessionDescription* current_description,
2080 const RtpHeaderExtensions& video_rtp_extensions,
2081 const VideoCodecs& video_codecs,
2082 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002083 SessionDescription* desc,
2084 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002085 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002086 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2087 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002088
kwiberg31022942016-03-11 14:18:21 -08002089 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002090 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002091 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2092 &crypto_suites);
2093
2094 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002095
2096 if (!media_description_options.codec_preferences.empty()) {
2097 // Add the codecs from the current transceiver's codec preferences.
2098 // They override any existing codecs from previous negotiations.
2099 filtered_codecs = MatchCodecPreference(
2100 media_description_options.codec_preferences, video_codecs_);
2101 } else {
2102 // Add the codecs from current content if it exists and is not rejected nor
2103 // recycled.
2104 if (current_content && !current_content->rejected &&
2105 current_content->name == media_description_options.mid) {
2106 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2107 const VideoContentDescription* vcd =
2108 current_content->media_description()->as_video();
2109 for (const VideoCodec& codec : vcd->codecs()) {
2110 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2111 nullptr)) {
2112 filtered_codecs.push_back(codec);
2113 }
zhihuang1c378ed2017-08-17 14:10:50 -07002114 }
2115 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002116 // Add other supported video codecs.
2117 VideoCodec found_codec;
2118 for (const VideoCodec& codec : video_codecs_) {
2119 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2120 &found_codec) &&
2121 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2122 nullptr)) {
2123 // Use the |found_codec| from |video_codecs| because it has the
2124 // correctly mapped payload type.
2125 filtered_codecs.push_back(found_codec);
2126 }
zhihuang1c378ed2017-08-17 14:10:50 -07002127 }
2128 }
2129
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002130 if (session_options.raw_packetization_for_video) {
2131 for (VideoCodec& codec : filtered_codecs) {
2132 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2133 codec.packetization = kPacketizationParamRaw;
2134 }
2135 }
2136 }
2137
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002138 if (!CreateMediaContentOffer(media_description_options, session_options,
2139 filtered_codecs, sdes_policy,
2140 GetCryptos(current_content), crypto_suites,
2141 video_rtp_extensions, ssrc_generator_,
2142 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002143 return false;
2144 }
2145
zhihuang1c378ed2017-08-17 14:10:50 -07002146 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002147
2148 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2149 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002150
Steve Anton4e70a722017-11-28 14:57:10 -08002151 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002152
Steve Anton5adfafd2017-12-20 16:34:00 -08002153 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002154 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002155 if (!AddTransportOffer(media_description_options.mid,
2156 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002157 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002158 return false;
2159 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002160 return true;
2161}
2162
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002163bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2164 const MediaDescriptionOptions& media_description_options,
2165 const MediaSessionOptions& session_options,
2166 const ContentInfo* current_content,
2167 const SessionDescription* current_description,
2168 StreamParamsVec* current_streams,
2169 SessionDescription* desc,
2170 IceCredentialsIterator* ice_credentials) const {
2171 std::unique_ptr<SctpDataContentDescription> data(
2172 new SctpDataContentDescription());
2173
2174 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2175
2176 cricket::SecurePolicy sdes_policy =
2177 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2178 : secure();
2179 std::vector<std::string> crypto_suites;
2180 // SDES doesn't make sense for SCTP, so we disable it, and we only
2181 // get SDES crypto suites for RTP-based data channels.
2182 sdes_policy = cricket::SEC_DISABLED;
2183 // Unlike SetMediaProtocol below, we need to set the protocol
2184 // before we call CreateMediaContentOffer. Otherwise,
2185 // CreateMediaContentOffer won't know this is SCTP and will
2186 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002187 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002188 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002189 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002190 data->set_max_message_size(kSctpSendBufferSize);
2191
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002192 if (!CreateContentOffer(media_description_options, session_options,
2193 sdes_policy, GetCryptos(current_content),
2194 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2195 current_streams, data.get())) {
2196 return false;
2197 }
2198
2199 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002200 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002201 if (!AddTransportOffer(media_description_options.mid,
2202 media_description_options.transport_options,
2203 current_description, desc, ice_credentials)) {
2204 return false;
2205 }
2206 return true;
2207}
2208
2209bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2210 const MediaDescriptionOptions& media_description_options,
2211 const MediaSessionOptions& session_options,
2212 const ContentInfo* current_content,
2213 const SessionDescription* current_description,
2214 const RtpDataCodecs& rtp_data_codecs,
2215 StreamParamsVec* current_streams,
2216 SessionDescription* desc,
2217 IceCredentialsIterator* ice_credentials) const {
2218 std::unique_ptr<RtpDataContentDescription> data(
2219 new RtpDataContentDescription());
2220 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2221
2222 cricket::SecurePolicy sdes_policy =
2223 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2224 : secure();
2225 std::vector<std::string> crypto_suites;
2226 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2227 &crypto_suites);
2228 if (!CreateMediaContentOffer(media_description_options, session_options,
2229 rtp_data_codecs, sdes_policy,
2230 GetCryptos(current_content), crypto_suites,
2231 RtpHeaderExtensions(), ssrc_generator_,
2232 current_streams, data.get())) {
2233 return false;
2234 }
2235
2236 data->set_bandwidth(kDataMaxBandwidth);
2237 SetMediaProtocol(secure_transport, data.get());
2238 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002239 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002240 if (!AddTransportOffer(media_description_options.mid,
2241 media_description_options.transport_options,
2242 current_description, desc, ice_credentials)) {
2243 return false;
2244 }
2245 return true;
2246}
2247
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002248bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002249 const MediaDescriptionOptions& media_description_options,
2250 const MediaSessionOptions& session_options,
2251 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002252 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002253 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002254 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002255 SessionDescription* desc,
2256 IceCredentialsIterator* ice_credentials) const {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07002257 bool is_sctp =
2258 (session_options.data_channel_type == DCT_SCTP ||
2259 session_options.data_channel_type == DCT_DATA_CHANNEL_TRANSPORT_SCTP);
zhihuang1c378ed2017-08-17 14:10:50 -07002260 // If the DataChannel type is not specified, use the DataChannel type in
2261 // the current description.
2262 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002263 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002264 is_sctp = (current_content->media_description()->protocol() ==
2265 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002266 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002267 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002268 return AddSctpDataContentForOffer(
2269 media_description_options, session_options, current_content,
2270 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002271 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002272 return AddRtpDataContentForOffer(media_description_options, session_options,
2273 current_content, current_description,
2274 rtp_data_codecs, current_streams, desc,
2275 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002276 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002277}
2278
zhihuang1c378ed2017-08-17 14:10:50 -07002279// |audio_codecs| = set of all possible codecs that can be used, with correct
2280// payload type mappings
2281//
2282// |supported_audio_codecs| = set of codecs that are supported for the direction
2283// of this m= section
2284//
2285// acd->codecs() = set of previously negotiated codecs for this m= section
2286//
2287// The payload types should come from audio_codecs, but the order should come
2288// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2289// change existing codec priority, and that new codecs are added with the right
2290// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002291bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002292 const MediaDescriptionOptions& media_description_options,
2293 const MediaSessionOptions& session_options,
2294 const ContentInfo* offer_content,
2295 const SessionDescription* offer_description,
2296 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002297 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002298 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002299 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002300 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002301 SessionDescription* answer,
2302 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002303 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002304 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002305 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002306
Steve Anton1a9d3c32018-12-10 17:18:54 -08002307 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002308 media_description_options.mid, offer_description,
2309 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002310 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002311 if (!audio_transport) {
2312 return false;
2313 }
2314
zhihuang1c378ed2017-08-17 14:10:50 -07002315 // Pick codecs based on the requested communications direction in the offer
2316 // and the selected direction in the answer.
2317 // Note these will be filtered one final time in CreateMediaContentAnswer.
2318 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002319 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002320 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002321 AudioCodecs supported_audio_codecs =
2322 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2323
2324 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002325
2326 if (!media_description_options.codec_preferences.empty()) {
2327 filtered_codecs = MatchCodecPreference(
2328 media_description_options.codec_preferences, supported_audio_codecs);
2329 } else {
2330 // Add the codecs from current content if it exists and is not rejected nor
2331 // recycled.
2332 if (current_content && !current_content->rejected &&
2333 current_content->name == media_description_options.mid) {
2334 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2335 const AudioContentDescription* acd =
2336 current_content->media_description()->as_audio();
2337 for (const AudioCodec& codec : acd->codecs()) {
2338 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2339 nullptr)) {
2340 filtered_codecs.push_back(codec);
2341 }
zhihuang1c378ed2017-08-17 14:10:50 -07002342 }
2343 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002344 // Add other supported audio codecs.
2345 for (const AudioCodec& codec : supported_audio_codecs) {
2346 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2347 codec, nullptr) &&
2348 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2349 filtered_codecs, codec, nullptr)) {
2350 // We should use the local codec with local parameters and the codec id
2351 // would be correctly mapped in |NegotiateCodecs|.
2352 filtered_codecs.push_back(codec);
2353 }
zhihuang1c378ed2017-08-17 14:10:50 -07002354 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002355 }
2356
zhihuang1c378ed2017-08-17 14:10:50 -07002357 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2358 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002359 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002360 new AudioContentDescription());
2361 // Do not require or create SDES cryptos if DTLS is used.
2362 cricket::SecurePolicy sdes_policy =
2363 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002364 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2365 media_description_options, session_options,
2366 ssrc_generator_, current_streams,
2367 audio_answer.get())) {
2368 return false;
2369 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002370 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002371 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002372 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002373 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002374 enable_encrypted_rtp_header_extensions_, current_streams,
2375 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002376 return false; // Fails the session setup.
2377 }
2378
deadbeefb7892532017-02-22 19:35:18 -08002379 bool secure = bundle_transport ? bundle_transport->description.secure()
2380 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002381 bool rejected = media_description_options.stopped ||
2382 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002383 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2384 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002385 if (!AddTransportAnswer(media_description_options.mid,
2386 *(audio_transport.get()), answer)) {
2387 return false;
2388 }
2389
2390 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002391 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2392 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002393 }
2394
zhihuang1c378ed2017-08-17 14:10:50 -07002395 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002396 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002397 return true;
2398}
2399
2400bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002401 const MediaDescriptionOptions& media_description_options,
2402 const MediaSessionOptions& session_options,
2403 const ContentInfo* offer_content,
2404 const SessionDescription* offer_description,
2405 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002406 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002407 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002408 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002409 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002410 SessionDescription* answer,
2411 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002412 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002413 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002414 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002415
Steve Anton1a9d3c32018-12-10 17:18:54 -08002416 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002417 media_description_options.mid, offer_description,
2418 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002419 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002420 if (!video_transport) {
2421 return false;
2422 }
2423
zhihuang1c378ed2017-08-17 14:10:50 -07002424 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002425
2426 if (!media_description_options.codec_preferences.empty()) {
2427 filtered_codecs = MatchCodecPreference(
2428 media_description_options.codec_preferences, video_codecs_);
2429 } else {
2430 // Add the codecs from current content if it exists and is not rejected nor
2431 // recycled.
2432 if (current_content && !current_content->rejected &&
2433 current_content->name == media_description_options.mid) {
2434 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2435 const VideoContentDescription* vcd =
2436 current_content->media_description()->as_video();
2437 for (const VideoCodec& codec : vcd->codecs()) {
2438 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2439 nullptr)) {
2440 filtered_codecs.push_back(codec);
2441 }
zhihuang1c378ed2017-08-17 14:10:50 -07002442 }
2443 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002444 // Add other supported video codecs.
2445 for (const VideoCodec& codec : video_codecs_) {
2446 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2447 nullptr) &&
2448 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2449 nullptr)) {
2450 // We should use the local codec with local parameters and the codec id
2451 // would be correctly mapped in |NegotiateCodecs|.
2452 filtered_codecs.push_back(codec);
2453 }
zhihuang1c378ed2017-08-17 14:10:50 -07002454 }
2455 }
2456
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002457 if (session_options.raw_packetization_for_video) {
2458 for (VideoCodec& codec : filtered_codecs) {
2459 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2460 codec.packetization = kPacketizationParamRaw;
2461 }
2462 }
2463 }
2464
zhihuang1c378ed2017-08-17 14:10:50 -07002465 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2466 session_options.bundle_enabled;
2467
kwiberg31022942016-03-11 14:18:21 -08002468 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002469 new VideoContentDescription());
2470 // Do not require or create SDES cryptos if DTLS is used.
2471 cricket::SecurePolicy sdes_policy =
2472 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002473 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2474 media_description_options, session_options,
2475 ssrc_generator_, current_streams,
2476 video_answer.get())) {
2477 return false;
2478 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002479 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002480 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002481 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002482 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002483 enable_encrypted_rtp_header_extensions_, current_streams,
2484 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002485 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002486 }
deadbeefb7892532017-02-22 19:35:18 -08002487 bool secure = bundle_transport ? bundle_transport->description.secure()
2488 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002489 bool rejected = media_description_options.stopped ||
2490 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002491 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2492 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002493 if (!AddTransportAnswer(media_description_options.mid,
2494 *(video_transport.get()), answer)) {
2495 return false;
2496 }
2497
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002498 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002499 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002500 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002501 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2502 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002503 }
zhihuang1c378ed2017-08-17 14:10:50 -07002504 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002505 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002506 return true;
2507}
2508
2509bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002510 const MediaDescriptionOptions& media_description_options,
2511 const MediaSessionOptions& session_options,
2512 const ContentInfo* offer_content,
2513 const SessionDescription* offer_description,
2514 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002515 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002516 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002517 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002518 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002519 SessionDescription* answer,
2520 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002521 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002522 media_description_options.mid, offer_description,
2523 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002524 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002525 if (!data_transport) {
2526 return false;
2527 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002528
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002529 // Do not require or create SDES cryptos if DTLS is used.
2530 cricket::SecurePolicy sdes_policy =
2531 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002532 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2533 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002534 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002535 std::unique_ptr<MediaContentDescription> data_answer;
2536 if (offer_content->media_description()->as_sctp()) {
2537 // SCTP data content
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002538 data_answer = std::make_unique<SctpDataContentDescription>();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002539 const SctpDataContentDescription* offer_data_description =
2540 offer_content->media_description()->as_sctp();
2541 // Respond with the offerer's proto, whatever it is.
2542 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002543 // Respond with our max message size or the remote max messsage size,
2544 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002545 // 0 is treated specially - it means "I can accept any size". Since
2546 // we do not implement infinite size messages, reply with
2547 // kSctpSendBufferSize.
2548 if (offer_data_description->max_message_size() == 0) {
2549 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2550 } else {
2551 data_answer->as_sctp()->set_max_message_size(std::min(
2552 offer_data_description->max_message_size(), kSctpSendBufferSize));
2553 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002554 if (!CreateMediaContentAnswer(
2555 offer_data_description, media_description_options, session_options,
2556 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2557 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2558 current_streams, bundle_enabled, data_answer.get())) {
2559 return false; // Fails the session setup.
2560 }
2561 // Respond with sctpmap if the offer uses sctpmap.
2562 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2563 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2564 } else {
2565 // RTP offer
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002566 data_answer = std::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002567
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002568 const RtpDataContentDescription* offer_data_description =
2569 offer_content->media_description()->as_rtp_data();
2570 RTC_CHECK(offer_data_description);
2571 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2572 media_description_options, session_options,
2573 ssrc_generator_, current_streams,
2574 data_answer->as_rtp_data())) {
2575 return false;
2576 }
2577 if (!CreateMediaContentAnswer(
2578 offer_data_description, media_description_options, session_options,
2579 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2580 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2581 current_streams, bundle_enabled, data_answer.get())) {
2582 return false; // Fails the session setup.
2583 }
2584 }
Steve Anton46afbf92019-05-10 11:15:18 -07002585
deadbeefb7892532017-02-22 19:35:18 -08002586 bool secure = bundle_transport ? bundle_transport->description.secure()
2587 : data_transport->secure();
2588
zhihuang1c378ed2017-08-17 14:10:50 -07002589 bool rejected = session_options.data_channel_type == DCT_NONE ||
2590 media_description_options.stopped ||
2591 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002592 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2593 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002594 if (!AddTransportAnswer(media_description_options.mid,
2595 *(data_transport.get()), answer)) {
2596 return false;
2597 }
2598
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002599 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002600 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002601 } else {
2602 // RFC 3264
2603 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002604 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002605 }
zhihuang1c378ed2017-08-17 14:10:50 -07002606 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002607 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002608 return true;
2609}
2610
zhihuang1c378ed2017-08-17 14:10:50 -07002611void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2612 audio_sendrecv_codecs_.clear();
2613 all_audio_codecs_.clear();
2614 // Compute the audio codecs union.
2615 for (const AudioCodec& send : audio_send_codecs_) {
2616 all_audio_codecs_.push_back(send);
2617 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2618 send, nullptr)) {
2619 // It doesn't make sense to have an RTX codec we support sending but not
2620 // receiving.
2621 RTC_DCHECK(!IsRtxCodec(send));
2622 }
2623 }
2624 for (const AudioCodec& recv : audio_recv_codecs_) {
2625 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2626 recv, nullptr)) {
2627 all_audio_codecs_.push_back(recv);
2628 }
2629 }
2630 // Use NegotiateCodecs to merge our codec lists, since the operation is
2631 // essentially the same. Put send_codecs as the offered_codecs, which is the
2632 // order we'd like to follow. The reasoning is that encoding is usually more
2633 // expensive than decoding, and prioritizing a codec in the send list probably
2634 // means it's a codec we can handle efficiently.
2635 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002636 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002637}
2638
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002640 return (content && (content->type == MediaProtocolType::kRtp ||
2641 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642}
2643
2644bool IsAudioContent(const ContentInfo* content) {
2645 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2646}
2647
2648bool IsVideoContent(const ContentInfo* content) {
2649 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2650}
2651
2652bool IsDataContent(const ContentInfo* content) {
2653 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2654}
2655
deadbeef0ed85b22016-02-23 17:24:52 -08002656const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2657 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002658 for (const ContentInfo& content : contents) {
2659 if (IsMediaContentOfType(&content, media_type)) {
2660 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661 }
2662 }
deadbeef0ed85b22016-02-23 17:24:52 -08002663 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002664}
2665
2666const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2667 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2668}
2669
2670const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2671 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2672}
2673
2674const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2675 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2676}
2677
Steve Antonad7bffc2018-01-22 10:21:56 -08002678const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2679 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002680 if (sdesc == nullptr) {
2681 return nullptr;
2682 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683
2684 return GetFirstMediaContent(sdesc->contents(), media_type);
2685}
2686
2687const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2688 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2689}
2690
2691const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2692 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2693}
2694
2695const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2696 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2697}
2698
2699const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002700 const SessionDescription* sdesc,
2701 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002702 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002703 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704}
2705
2706const AudioContentDescription* GetFirstAudioContentDescription(
2707 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002708 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2709 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710}
2711
2712const VideoContentDescription* GetFirstVideoContentDescription(
2713 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002714 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2715 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716}
2717
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002718const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2719 const SessionDescription* sdesc) {
2720 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2721 return desc ? desc->as_rtp_data() : nullptr;
2722}
2723
2724const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2725 const SessionDescription* sdesc) {
2726 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2727 return desc ? desc->as_sctp() : nullptr;
2728}
2729
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002730//
2731// Non-const versions of the above functions.
2732//
2733
Steve Anton36b29d12017-10-30 09:57:42 -07002734ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002735 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002736 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002737 if (IsMediaContentOfType(&content, media_type)) {
2738 return &content;
2739 }
2740 }
2741 return nullptr;
2742}
2743
Steve Anton36b29d12017-10-30 09:57:42 -07002744ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002745 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2746}
2747
Steve Anton36b29d12017-10-30 09:57:42 -07002748ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002749 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2750}
2751
Steve Anton36b29d12017-10-30 09:57:42 -07002752ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002753 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2754}
2755
Steve Antonad7bffc2018-01-22 10:21:56 -08002756ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2757 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002758 if (sdesc == nullptr) {
2759 return nullptr;
2760 }
2761
Steve Anton36b29d12017-10-30 09:57:42 -07002762 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002763}
2764
2765ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2766 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2767}
2768
2769ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2770 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2771}
2772
2773ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2774 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2775}
2776
2777MediaContentDescription* GetFirstMediaContentDescription(
2778 SessionDescription* sdesc,
2779 MediaType media_type) {
2780 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002781 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002782}
2783
2784AudioContentDescription* GetFirstAudioContentDescription(
2785 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002786 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2787 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002788}
2789
2790VideoContentDescription* GetFirstVideoContentDescription(
2791 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002792 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2793 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002794}
2795
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002796RtpDataContentDescription* GetFirstRtpDataContentDescription(
2797 SessionDescription* sdesc) {
2798 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2799 return desc ? desc->as_rtp_data() : nullptr;
2800}
2801
2802SctpDataContentDescription* GetFirstSctpDataContentDescription(
2803 SessionDescription* sdesc) {
2804 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2805 return desc ? desc->as_sctp() : nullptr;
2806}
2807
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808} // namespace cricket