blob: fff2a4009215ff1e49d4549020681355b4c69e2f [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"
Steve Anton5c72e712018-12-10 14:25:30 -080022#include "absl/memory/memory.h"
Niels Möller2edab4c2018-10-22 09:48:08 +020023#include "absl/strings/match.h"
Danil Chapovalov66cadcc2018-06-19 16:47:43 +020024#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "media/base/h264_profile_level_id.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "media/base/media_constants.h"
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +020028#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "p2p/base/p2p_constants.h"
30#include "pc/channel_manager.h"
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020031#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/rtp_media_utils.h"
33#include "pc/srtp_filter.h"
Johannes Kron746dd0d2019-06-20 15:37:52 +020034#include "pc/used_ids.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "rtc_base/checks.h"
36#include "rtc_base/helpers.h"
37#include "rtc_base/logging.h"
Artem Titova76af0c2018-07-23 17:38:12 +020038#include "rtc_base/third_party/base64/base64.h"
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080039#include "rtc_base/unique_id_generator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040
41namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080042
Amit Hilbuchdbb49df2019-01-23 14:54:24 -080043using rtc::UniqueRandomIdGenerator;
Steve Anton1d03a752017-11-27 14:30:09 -080044using webrtc::RtpTransceiverDirection;
45
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080047
Benjamin Wrighta54daf12018-10-11 15:33:17 -070048void GetSupportedSdesCryptoSuiteNames(
49 void (*func)(const webrtc::CryptoOptions&, std::vector<int>*),
50 const webrtc::CryptoOptions& crypto_options,
51 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080052 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070053 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080054 for (const auto crypto : crypto_suites) {
55 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
56 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080057}
Elad Alon157540a2019-02-08 23:37:52 +010058
terelius8c011e52016-04-26 05:28:11 -070059} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
61namespace cricket {
62
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063// RTP Profile names
64// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
65// RFC4585
66const char kMediaProtocolAvpf[] = "RTP/AVPF";
67// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000068const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
69
deadbeeff3938292015-07-15 12:20:53 -070070// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
71// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072const char kMediaProtocolSavpf[] = "RTP/SAVPF";
73
deadbeef8b7e9ad2017-05-25 09:38:55 -070074// Note that the below functions support some protocol strings purely for
75// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
76// and Interoperability.
77
78static bool IsDtlsRtp(const std::string& protocol) {
79 // Most-likely values first.
80 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
81 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
82}
83
84static bool IsPlainRtp(const std::string& protocol) {
85 // Most-likely values first.
86 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
87 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
88}
89
Steve Anton1d03a752017-11-27 14:30:09 -080090static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
91 RtpTransceiverDirection offer,
92 RtpTransceiverDirection wants) {
93 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
94 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
95 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
96 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
97 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
98 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -070099}
100
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101static bool IsMediaContentOfType(const ContentInfo* content,
102 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800103 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 return false;
105 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800106 return content->media_description()->type() == media_type;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107}
108
Yves Gerey665174f2018-06-19 15:03:05 +0200109static bool CreateCryptoParams(int tag,
110 const std::string& cipher,
Steve Anton3a66edf2018-09-10 12:57:37 -0700111 CryptoParams* crypto_out) {
jbauchcb560652016-08-04 05:20:32 -0700112 int key_len;
113 int salt_len;
Yves Gerey665174f2018-06-19 15:03:05 +0200114 if (!rtc::GetSrtpKeyAndSaltLengths(rtc::SrtpCryptoSuiteFromName(cipher),
115 &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116 return false;
117 }
jbauchcb560652016-08-04 05:20:32 -0700118
119 int master_key_len = key_len + salt_len;
120 std::string master_key;
121 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
122 return false;
123 }
124
kwiberg352444f2016-11-28 15:58:53 -0800125 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700126 std::string key = rtc::Base64::Encode(master_key);
127
Steve Anton3a66edf2018-09-10 12:57:37 -0700128 crypto_out->tag = tag;
129 crypto_out->cipher_suite = cipher;
130 crypto_out->key_params = kInline;
131 crypto_out->key_params += key;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132 return true;
133}
134
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135static bool AddCryptoParams(const std::string& cipher_suite,
Steve Anton3a66edf2018-09-10 12:57:37 -0700136 CryptoParamsVec* cryptos_out) {
137 int size = static_cast<int>(cryptos_out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
Steve Anton3a66edf2018-09-10 12:57:37 -0700139 cryptos_out->resize(size + 1);
140 return CreateCryptoParams(size, cipher_suite, &cryptos_out->at(size));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141}
142
143void AddMediaCryptos(const CryptoParamsVec& cryptos,
144 MediaContentDescription* media) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700145 for (const CryptoParams& crypto : cryptos) {
146 media->AddCrypto(crypto);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147 }
148}
149
150bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
151 MediaContentDescription* media) {
152 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700153 for (const std::string& crypto_suite : crypto_suites) {
154 if (!AddCryptoParams(crypto_suite, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 return false;
156 }
157 }
158 AddMediaCryptos(cryptos, media);
159 return true;
160}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161
zhihuang1c378ed2017-08-17 14:10:50 -0700162const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800163 if (!content || !content->media_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -0700164 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800166 return &content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000167}
168
169bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
170 const CryptoParams& crypto,
Steve Anton3a66edf2018-09-10 12:57:37 -0700171 CryptoParams* crypto_out) {
Steve Anton64b626b2019-01-28 17:25:26 -0800172 auto it = absl::c_find_if(
173 cryptos, [&crypto](const CryptoParams& c) { return crypto.Matches(c); });
Steve Anton3a66edf2018-09-10 12:57:37 -0700174 if (it == cryptos.end()) {
175 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700177 *crypto_out = *it;
178 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179}
180
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700181// For audio, HMAC 32 (if enabled) is prefered over HMAC 80 because of the
182// low overhead.
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700183void GetSupportedAudioSdesCryptoSuites(
184 const webrtc::CryptoOptions& crypto_options,
185 std::vector<int>* crypto_suites) {
186 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
188 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
189 }
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700190 if (crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher) {
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700191 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
192 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800193 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000194}
195
deadbeef7914b8c2017-04-21 03:23:33 -0700196void GetSupportedAudioSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700197 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800198 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700199 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
200 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201}
202
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700203void GetSupportedVideoSdesCryptoSuites(
204 const webrtc::CryptoOptions& crypto_options,
205 std::vector<int>* crypto_suites) {
206 if (crypto_options.srtp.enable_gcm_crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700207 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
208 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
209 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800210 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211}
212
deadbeef7914b8c2017-04-21 03:23:33 -0700213void GetSupportedVideoSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700214 const webrtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800215 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700216 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
217 crypto_options, crypto_suite_names);
218}
219
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700220void GetSupportedDataSdesCryptoSuites(
221 const webrtc::CryptoOptions& crypto_options,
222 std::vector<int>* crypto_suites) {
223 if (crypto_options.srtp.enable_gcm_crypto_suites) {
deadbeef7914b8c2017-04-21 03:23:33 -0700224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
225 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
226 }
227 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
228}
229
230void GetSupportedDataSdesCryptoSuiteNames(
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700231 const webrtc::CryptoOptions& crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -0700232 std::vector<std::string>* crypto_suite_names) {
233 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
234 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800235}
236
jbauchcb560652016-08-04 05:20:32 -0700237// Support any GCM cipher (if enabled through options). For video support only
Taylor Brandstetter5e55fe82018-03-23 11:50:16 -0700238// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated (if enabled) unless
239// bundle is enabled because it is low overhead.
jbauchcb560652016-08-04 05:20:32 -0700240// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241static bool SelectCrypto(const MediaContentDescription* offer,
242 bool bundle,
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700243 const webrtc::CryptoOptions& crypto_options,
Steve Anton3a66edf2018-09-10 12:57:37 -0700244 CryptoParams* crypto_out) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
246 const CryptoParamsVec& cryptos = offer->cryptos();
247
Steve Anton3a66edf2018-09-10 12:57:37 -0700248 for (const CryptoParams& crypto : cryptos) {
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700249 if ((crypto_options.srtp.enable_gcm_crypto_suites &&
Steve Anton3a66edf2018-09-10 12:57:37 -0700250 rtc::IsGcmCryptoSuiteName(crypto.cipher_suite)) ||
251 rtc::CS_AES_CM_128_HMAC_SHA1_80 == crypto.cipher_suite ||
252 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == crypto.cipher_suite && audio &&
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700253 !bundle && crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher)) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700254 return CreateCryptoParams(crypto.tag, crypto.cipher_suite, crypto_out);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 }
256 }
257 return false;
258}
259
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260// Finds all StreamParams of all media types and attach them to stream_params.
Steve Anton5c72e712018-12-10 14:25:30 -0800261static StreamParamsVec GetCurrentStreamParams(
262 const std::vector<const ContentInfo*>& active_local_contents) {
263 StreamParamsVec stream_params;
264 for (const ContentInfo* content : active_local_contents) {
265 for (const StreamParams& params : content->media_description()->streams()) {
266 stream_params.push_back(params);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 }
268 }
Steve Anton5c72e712018-12-10 14:25:30 -0800269 return stream_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270}
271
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000272// Filters the data codecs for the data channel type.
273void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
274 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700275 const char* codec_name =
276 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
Steve Anton3a66edf2018-09-10 12:57:37 -0700277 codecs->erase(std::remove_if(codecs->begin(), codecs->end(),
278 [&codec_name](const DataCodec& codec) {
Niels Möller039743e2018-10-23 10:07:25 +0200279 return absl::EqualsIgnoreCase(codec.name,
280 codec_name);
Steve Anton3a66edf2018-09-10 12:57:37 -0700281 }),
282 codecs->end());
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000283}
284
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800285static StreamParams CreateStreamParamsForNewSenderWithSsrcs(
286 const SenderOptions& sender,
287 const std::string& rtcp_cname,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800288 bool include_rtx_streams,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800289 bool include_flexfec_stream,
290 UniqueRandomIdGenerator* ssrc_generator) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800291 StreamParams result;
292 result.id = sender.track_id;
293
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800294 // TODO(brandtr): Update when we support multistream protection.
295 if (include_flexfec_stream && sender.num_sim_layers > 1) {
296 include_flexfec_stream = false;
297 RTC_LOG(LS_WARNING)
298 << "Our FlexFEC implementation only supports protecting "
299 "a single media streams. This session has multiple "
300 "media streams however, so no FlexFEC SSRC will be generated.";
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800301 }
302
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800303 result.GenerateSsrcs(sender.num_sim_layers, include_rtx_streams,
304 include_flexfec_stream, ssrc_generator);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800305
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800306 result.cname = rtcp_cname;
307 result.set_stream_ids(sender.stream_ids);
308
309 return result;
310}
311
312static bool ValidateSimulcastLayers(
313 const std::vector<RidDescription>& rids,
314 const SimulcastLayerList& simulcast_layers) {
Steve Anton64b626b2019-01-28 17:25:26 -0800315 return absl::c_all_of(
316 simulcast_layers.GetAllLayers(), [&rids](const SimulcastLayer& layer) {
317 return absl::c_any_of(rids, [&layer](const RidDescription& rid) {
318 return rid.rid == layer.rid;
319 });
320 });
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800321}
322
323static StreamParams CreateStreamParamsForNewSenderWithRids(
324 const SenderOptions& sender,
325 const std::string& rtcp_cname) {
326 RTC_DCHECK(!sender.rids.empty());
327 RTC_DCHECK_EQ(sender.num_sim_layers, 0)
328 << "RIDs are the compliant way to indicate simulcast.";
329 RTC_DCHECK(ValidateSimulcastLayers(sender.rids, sender.simulcast_layers));
330 StreamParams result;
331 result.id = sender.track_id;
332 result.cname = rtcp_cname;
333 result.set_stream_ids(sender.stream_ids);
334
335 // More than one rid should be signaled.
336 if (sender.rids.size() > 1) {
337 result.set_rids(sender.rids);
338 }
339
340 return result;
341}
342
343// Adds SimulcastDescription if indicated by the media description options.
344// MediaContentDescription should already be set up with the send rids.
345static void AddSimulcastToMediaDescription(
346 const MediaDescriptionOptions& media_description_options,
347 MediaContentDescription* description) {
348 RTC_DCHECK(description);
349
350 // Check if we are using RIDs in this scenario.
Steve Anton64b626b2019-01-28 17:25:26 -0800351 if (absl::c_all_of(description->streams(), [](const StreamParams& params) {
352 return !params.has_rids();
353 })) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800354 return;
355 }
356
357 RTC_DCHECK_EQ(1, description->streams().size())
358 << "RIDs are only supported in Unified Plan semantics.";
359 RTC_DCHECK_EQ(1, media_description_options.sender_options.size());
360 RTC_DCHECK(description->type() == MediaType::MEDIA_TYPE_AUDIO ||
361 description->type() == MediaType::MEDIA_TYPE_VIDEO);
362
363 // One RID or less indicates that simulcast is not needed.
364 if (description->streams()[0].rids().size() <= 1) {
365 return;
366 }
367
Amit Hilbuchb7446ed2019-01-28 12:25:25 -0800368 // Only negotiate the send layers.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800369 SimulcastDescription simulcast;
370 simulcast.send_layers() =
371 media_description_options.sender_options[0].simulcast_layers;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372 description->set_simulcast_description(simulcast);
373}
374
zhihuang1c378ed2017-08-17 14:10:50 -0700375// Adds a StreamParams for each SenderOptions in |sender_options| to
376// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000377// |current_params| - All currently known StreamParams of any media type.
378template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700379static bool AddStreamParams(
380 const std::vector<SenderOptions>& sender_options,
381 const std::string& rtcp_cname,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800382 UniqueRandomIdGenerator* ssrc_generator,
zhihuang1c378ed2017-08-17 14:10:50 -0700383 StreamParamsVec* current_streams,
384 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700385 // SCTP streams are not negotiated using SDP/ContentDescriptions.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200386 if (IsSctpProtocol(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700387 return true;
388 }
389
Noah Richards2e7a0982015-05-18 14:02:54 -0700390 const bool include_rtx_streams =
391 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000392
brandtr03d5fb12016-11-22 03:37:59 -0800393 const bool include_flexfec_stream =
394 ContainsFlexfecCodec(content_description->codecs());
395
zhihuang1c378ed2017-08-17 14:10:50 -0700396 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397 // groupid is empty for StreamParams generated using
398 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700399 StreamParams* param =
400 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000401 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700402 // This is a new sender.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800403 StreamParams stream_param =
404 sender.rids.empty()
405 ?
406 // Signal SSRCs and legacy simulcast (if requested).
407 CreateStreamParamsForNewSenderWithSsrcs(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800408 sender, rtcp_cname, include_rtx_streams,
409 include_flexfec_stream, ssrc_generator)
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 :
411 // Signal RIDs and spec-compliant simulcast (if requested).
412 CreateStreamParamsForNewSenderWithRids(sender, rtcp_cname);
413
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414 content_description->AddStream(stream_param);
415
416 // Store the new StreamParams in current_streams.
417 // This is necessary so that we can use the CNAME for other media types.
418 current_streams->push_back(stream_param);
419 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700420 // Use existing generated SSRCs/groups, but update the sync_label if
421 // necessary. This may be needed if a MediaStreamTrack was moved from one
422 // MediaStream to another.
Seth Hampson845e8782018-03-02 11:34:10 -0800423 param->set_stream_ids(sender.stream_ids);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000424 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 }
426 }
427 return true;
428}
429
430// Updates the transport infos of the |sdesc| according to the given
431// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800432// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
433// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
435 SessionDescription* sdesc) {
436 // The bundle should not be empty.
437 if (!sdesc || !bundle_group.FirstContentName()) {
438 return false;
439 }
440
441 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700442 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 const TransportInfo* selected_transport_info =
444 sdesc->GetTransportInfoByName(selected_content_name);
445 if (!selected_transport_info) {
446 return false;
447 }
448
449 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700450 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000451 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700452 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800454 ConnectionRole selected_connection_role =
455 selected_transport_info->description.connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700456 const absl::optional<OpaqueTransportParameters>& selected_opaque_parameters =
457 selected_transport_info->description.opaque_parameters;
Steve Anton3a66edf2018-09-10 12:57:37 -0700458 for (TransportInfo& transport_info : sdesc->transport_infos()) {
459 if (bundle_group.HasContentName(transport_info.content_name) &&
460 transport_info.content_name != selected_content_name) {
461 transport_info.description.ice_ufrag = selected_ufrag;
462 transport_info.description.ice_pwd = selected_pwd;
463 transport_info.description.connection_role = selected_connection_role;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700464 transport_info.description.opaque_parameters = selected_opaque_parameters;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 }
466 }
467 return true;
468}
469
470// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
471// sets it to |cryptos|.
472static bool GetCryptosByName(const SessionDescription* sdesc,
473 const std::string& content_name,
474 CryptoParamsVec* cryptos) {
475 if (!sdesc || !cryptos) {
476 return false;
477 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478 const ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800479 if (!content || !content->media_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480 return false;
481 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800482 *cryptos = content->media_description()->cryptos();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 return true;
484}
485
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000486// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
487// which are not available in |filter|.
488static void PruneCryptos(const CryptoParamsVec& filter,
489 CryptoParamsVec* target_cryptos) {
490 if (!target_cryptos) {
491 return;
492 }
tzik21995802018-04-26 17:38:28 +0900493
494 target_cryptos->erase(
495 std::remove_if(target_cryptos->begin(), target_cryptos->end(),
496 // Returns true if the |crypto|'s cipher_suite is not
497 // found in |filter|.
498 [&filter](const CryptoParams& crypto) {
499 for (const CryptoParams& entry : filter) {
500 if (entry.cipher_suite == crypto.cipher_suite)
501 return false;
502 }
503 return true;
504 }),
505 target_cryptos->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506}
507
508static bool IsRtpContent(SessionDescription* sdesc,
509 const std::string& content_name) {
510 bool is_rtp = false;
511 ContentInfo* content = sdesc->GetContentByName(content_name);
Steve Antonb1c1de12017-12-21 15:14:30 -0800512 if (content && content->media_description()) {
513 is_rtp = IsRtpProtocol(content->media_description()->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 }
515 return is_rtp;
516}
517
518// Updates the crypto parameters of the |sdesc| according to the given
519// |bundle_group|. The crypto parameters of all the contents within the
520// |bundle_group| should be updated to use the common subset of the
521// available cryptos.
522static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
523 SessionDescription* sdesc) {
524 // The bundle should not be empty.
525 if (!sdesc || !bundle_group.FirstContentName()) {
526 return false;
527 }
528
wu@webrtc.org78187522013-10-07 23:32:02 +0000529 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 // Get the common cryptos.
531 const ContentNames& content_names = bundle_group.content_names();
532 CryptoParamsVec common_cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700533 bool first = true;
534 for (const std::string& content_name : content_names) {
535 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 continue;
537 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000538 // The common cryptos are needed if any of the content does not have DTLS
539 // enabled.
Steve Anton3a66edf2018-09-10 12:57:37 -0700540 if (!sdesc->GetTransportInfoByName(content_name)->description.secure()) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000541 common_cryptos_needed = true;
542 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700543 if (first) {
544 first = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 // Initial the common_cryptos with the first content in the bundle group.
Steve Anton3a66edf2018-09-10 12:57:37 -0700546 if (!GetCryptosByName(sdesc, content_name, &common_cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 return false;
548 }
549 if (common_cryptos.empty()) {
550 // If there's no crypto params, we should just return.
551 return true;
552 }
553 } else {
554 CryptoParamsVec cryptos;
Steve Anton3a66edf2018-09-10 12:57:37 -0700555 if (!GetCryptosByName(sdesc, content_name, &cryptos)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 return false;
557 }
558 PruneCryptos(cryptos, &common_cryptos);
559 }
560 }
561
wu@webrtc.org78187522013-10-07 23:32:02 +0000562 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 return false;
564 }
565
566 // Update to use the common cryptos.
Steve Anton3a66edf2018-09-10 12:57:37 -0700567 for (const std::string& content_name : content_names) {
568 if (!IsRtpContent(sdesc, content_name)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 continue;
570 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700571 ContentInfo* content = sdesc->GetContentByName(content_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 if (IsMediaContent(content)) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800573 MediaContentDescription* media_desc = content->media_description();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 if (!media_desc) {
575 return false;
576 }
577 media_desc->set_cryptos(common_cryptos);
578 }
579 }
580 return true;
581}
582
Steve Anton5c72e712018-12-10 14:25:30 -0800583static std::vector<const ContentInfo*> GetActiveContents(
584 const SessionDescription& description,
585 const MediaSessionOptions& session_options) {
586 std::vector<const ContentInfo*> active_contents;
587 for (size_t i = 0; i < description.contents().size(); ++i) {
588 RTC_DCHECK_LT(i, session_options.media_description_options.size());
589 const ContentInfo& content = description.contents()[i];
590 const MediaDescriptionOptions& media_options =
591 session_options.media_description_options[i];
592 if (!content.rejected && !media_options.stopped &&
593 content.name == media_options.mid) {
594 active_contents.push_back(&content);
595 }
596 }
597 return active_contents;
598}
599
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600template <class C>
601static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800602 for (const auto& codec : codecs) {
603 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 return true;
605 }
606 }
607 return false;
608}
609
610template <class C>
611static bool IsRtxCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200612 return absl::EqualsIgnoreCase(codec.name, kRtxCodecName);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613}
614
brandtr03d5fb12016-11-22 03:37:59 -0800615template <class C>
616static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
617 for (const auto& codec : codecs) {
618 if (IsFlexfecCodec(codec)) {
619 return true;
620 }
621 }
622 return false;
623}
624
625template <class C>
626static bool IsFlexfecCodec(const C& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +0200627 return absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName);
brandtr03d5fb12016-11-22 03:37:59 -0800628}
629
zhihuang1c378ed2017-08-17 14:10:50 -0700630// Create a media content to be offered for the given |sender_options|,
631// according to the given options.rtcp_mux, session_options.is_muc, codecs,
632// secure_transport, crypto, and current_streams. If we don't currently have
633// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
634// created (according to crypto_suites). The created content is added to the
635// offer.
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200636static bool CreateContentOffer(
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800637 const MediaDescriptionOptions& media_description_options,
zhihuang1c378ed2017-08-17 14:10:50 -0700638 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000639 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 const CryptoParamsVec* current_cryptos,
641 const std::vector<std::string>& crypto_suites,
642 const RtpHeaderExtensions& rtp_extensions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800643 UniqueRandomIdGenerator* ssrc_generator,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 StreamParamsVec* current_streams,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200645 MediaContentDescription* offer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700646 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700647 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
648 offer->set_rtcp_reduced_size(true);
649 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 offer->set_rtp_header_extensions(rtp_extensions);
651
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800652 AddSimulcastToMediaDescription(media_description_options, offer);
653
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 if (secure_policy != SEC_DISABLED) {
655 if (current_cryptos) {
656 AddMediaCryptos(*current_cryptos, offer);
657 }
658 if (offer->cryptos().empty()) {
659 if (!CreateMediaCryptos(crypto_suites, offer)) {
660 return false;
661 }
662 }
663 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664
deadbeef7af91dd2016-12-13 11:29:11 -0800665 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 return false;
667 }
668 return true;
669}
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200670template <class C>
671static bool CreateMediaContentOffer(
672 const MediaDescriptionOptions& media_description_options,
673 const MediaSessionOptions& session_options,
674 const std::vector<C>& codecs,
675 const SecurePolicy& secure_policy,
676 const CryptoParamsVec* current_cryptos,
677 const std::vector<std::string>& crypto_suites,
678 const RtpHeaderExtensions& rtp_extensions,
679 UniqueRandomIdGenerator* ssrc_generator,
680 StreamParamsVec* current_streams,
681 MediaContentDescriptionImpl<C>* offer) {
682 offer->AddCodecs(codecs);
683 if (!AddStreamParams(media_description_options.sender_options,
684 session_options.rtcp_cname, ssrc_generator,
685 current_streams, offer)) {
686 return false;
687 }
688
689 return CreateContentOffer(media_description_options, session_options,
690 secure_policy, current_cryptos, crypto_suites,
691 rtp_extensions, ssrc_generator, current_streams,
692 offer);
693}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694
695template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000696static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800697 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000698 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800699 const int codec2_id) {
700 const C* codec1 = FindCodecById(codecs1, codec1_id);
701 const C* codec2 = FindCodecById(codecs2, codec2_id);
702 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000703}
704
705template <class C>
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200706static void NegotiatePacketization(const C& local_codec,
707 const C& remote_codec,
708 C* negotiated_codec) {}
709
710template <>
711void NegotiatePacketization(const VideoCodec& local_codec,
712 const VideoCodec& remote_codec,
713 VideoCodec* negotiated_codec) {
714 negotiated_codec->packetization =
715 VideoCodec::IntersectPacketization(local_codec, remote_codec);
716}
717
718template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000719static void NegotiateCodecs(const std::vector<C>& local_codecs,
720 const std::vector<C>& offered_codecs,
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200721 std::vector<C>* negotiated_codecs,
722 bool keep_offer_order) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800723 for (const C& ours : local_codecs) {
724 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700725 // Note that we intentionally only find one matching codec for each of our
726 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800727 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
728 C negotiated = ours;
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200729 NegotiatePacketization(ours, theirs, &negotiated);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800730 negotiated.IntersectFeedbackParams(theirs);
731 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800732 const auto apt_it =
733 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800734 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800735 RTC_DCHECK(apt_it != theirs.params.end());
736 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 }
Niels Möller039743e2018-10-23 10:07:25 +0200738 if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
magjedf823ede2016-11-12 09:53:04 -0800739 webrtc::H264::GenerateProfileLevelIdForAnswer(
740 ours.params, theirs.params, &negotiated.params);
741 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800742 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700743 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800744 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 }
746 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200747 if (keep_offer_order) {
748 // RFC3264: Although the answerer MAY list the formats in their desired
749 // order of preference, it is RECOMMENDED that unless there is a
750 // specific reason, the answerer list formats in the same relative order
751 // they were present in the offer.
752 // This can be skipped when the transceiver has any codec preferences.
753 std::unordered_map<int, int> payload_type_preferences;
754 int preference = static_cast<int>(offered_codecs.size() + 1);
755 for (const C& codec : offered_codecs) {
756 payload_type_preferences[codec.id] = preference--;
757 }
758 absl::c_sort(*negotiated_codecs, [&payload_type_preferences](const C& a,
759 const C& b) {
760 return payload_type_preferences[a.id] > payload_type_preferences[b.id];
761 });
deadbeef67cf2c12016-04-13 10:07:16 -0700762 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763}
764
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800765// Finds a codec in |codecs2| that matches |codec_to_match|, which is
766// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
767// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800769static bool FindMatchingCodec(const std::vector<C>& codecs1,
770 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 const C& codec_to_match,
772 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700773 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
774 // codecs' associated codecs correctly. If not, that's a programming error.
Steve Anton64b626b2019-01-28 17:25:26 -0800775 RTC_DCHECK(absl::c_any_of(codecs1, [&codec_to_match](const C& codec) {
776 return &codec == &codec_to_match;
777 }));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800778 for (const C& potential_match : codecs2) {
779 if (potential_match.Matches(codec_to_match)) {
780 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800781 int apt_value_1 = 0;
782 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800783 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
784 &apt_value_1) ||
785 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
786 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100787 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800788 continue;
789 }
790 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
791 apt_value_2)) {
792 continue;
793 }
794 }
795 if (found_codec) {
796 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 }
798 return true;
799 }
800 }
801 return false;
802}
803
zhihuang1c378ed2017-08-17 14:10:50 -0700804// Find the codec in |codec_list| that |rtx_codec| is associated with.
805template <class C>
806static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
807 const C& rtx_codec) {
808 std::string associated_pt_str;
809 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
810 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100811 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
812 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700813 return nullptr;
814 }
815
816 int associated_pt;
817 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100818 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
819 << " of RTX codec " << rtx_codec.name
820 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700821 return nullptr;
822 }
823
824 // Find the associated reference codec for the reference RTX codec.
825 const C* associated_codec = FindCodecById(codec_list, associated_pt);
826 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100827 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
828 << associated_pt << " for RTX codec " << rtx_codec.name
829 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700830 }
831 return associated_codec;
832}
833
834// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835// already exist in |offered_codecs| and ensure the payload types don't
836// collide.
837template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700838static void MergeCodecs(const std::vector<C>& reference_codecs,
839 std::vector<C>* offered_codecs,
840 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800842 for (const C& reference_codec : reference_codecs) {
843 if (!IsRtxCodec(reference_codec) &&
844 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
845 reference_codec, nullptr)) {
846 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 used_pltypes->FindAndSetIdUsed(&codec);
848 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 }
850 }
851
852 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800853 for (const C& reference_codec : reference_codecs) {
854 if (IsRtxCodec(reference_codec) &&
855 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
856 reference_codec, nullptr)) {
857 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700858 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700859 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700860 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700861 continue;
862 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800863 // Find a codec in the offered list that matches the reference codec.
864 // Its payload type may be different than the reference codec.
865 C matching_codec;
866 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800867 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100868 RTC_LOG(LS_WARNING)
869 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800870 continue;
871 }
872
873 rtx_codec.params[kCodecParamAssociatedPayloadType] =
874 rtc::ToString(matching_codec.id);
875 used_pltypes->FindAndSetIdUsed(&rtx_codec);
876 offered_codecs->push_back(rtx_codec);
877 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 }
879}
880
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200881template <typename Codecs>
882static Codecs MatchCodecPreference(
883 const std::vector<webrtc::RtpCodecCapability>& codec_preferences,
884 const Codecs& codecs) {
885 Codecs filtered_codecs;
886 std::set<std::string> kept_codecs_ids;
887 bool want_rtx = false;
888
889 for (const auto& codec_preference : codec_preferences) {
890 auto found_codec = absl::c_find_if(
891 codecs, [&codec_preference](const typename Codecs::value_type& codec) {
892 webrtc::RtpCodecParameters codec_parameters =
893 codec.ToCodecParameters();
894 return codec_parameters.name == codec_preference.name &&
895 codec_parameters.kind == codec_preference.kind &&
896 codec_parameters.num_channels ==
897 codec_preference.num_channels &&
898 codec_parameters.clock_rate == codec_preference.clock_rate &&
899 codec_parameters.parameters == codec_preference.parameters;
900 });
901
902 if (found_codec != codecs.end()) {
903 filtered_codecs.push_back(*found_codec);
904 kept_codecs_ids.insert(std::to_string(found_codec->id));
905 } else if (IsRtxCodec(codec_preference)) {
906 want_rtx = true;
907 }
908 }
909
910 if (want_rtx) {
911 for (const auto& codec : codecs) {
912 if (IsRtxCodec(codec)) {
913 const auto apt =
914 codec.params.find(cricket::kCodecParamAssociatedPayloadType);
915 if (apt != codec.params.end() &&
916 kept_codecs_ids.count(apt->second) > 0) {
917 filtered_codecs.push_back(codec);
918 }
919 }
920 }
921 }
922
923 return filtered_codecs;
924}
925
zhihuang1c378ed2017-08-17 14:10:50 -0700926static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
927 const webrtc::RtpExtension& ext_to_match,
928 webrtc::RtpExtension* found_extension) {
Steve Anton64b626b2019-01-28 17:25:26 -0800929 auto it = absl::c_find_if(
930 extensions, [&ext_to_match](const webrtc::RtpExtension& extension) {
931 // We assume that all URIs are given in a canonical
932 // format.
933 return extension.uri == ext_to_match.uri &&
934 extension.encrypt == ext_to_match.encrypt;
935 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700936 if (it == extensions.end()) {
937 return false;
zhihuang1c378ed2017-08-17 14:10:50 -0700938 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700939 if (found_extension) {
940 *found_extension = *it;
941 }
942 return true;
zhihuang1c378ed2017-08-17 14:10:50 -0700943}
944
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000945static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700946 const webrtc::RtpExtension& ext_to_match,
947 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700948 // We assume that all URIs are given in a canonical format.
949 const webrtc::RtpExtension* found =
950 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
951 ext_to_match.uri);
952 if (!found) {
953 return false;
954 }
955 if (found_extension) {
956 *found_extension = *found;
957 }
958 return true;
959}
960
961static bool FindByUriWithEncryptionPreference(
962 const RtpHeaderExtensions& extensions,
Yves Gerey665174f2018-06-19 15:03:05 +0200963 const webrtc::RtpExtension& ext_to_match,
964 bool encryption_preference,
jbauch5869f502017-06-29 12:31:36 -0700965 webrtc::RtpExtension* found_extension) {
966 const webrtc::RtpExtension* unencrypted_extension = nullptr;
Steve Anton3a66edf2018-09-10 12:57:37 -0700967 for (const webrtc::RtpExtension& extension : extensions) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968 // We assume that all URIs are given in a canonical format.
Steve Anton3a66edf2018-09-10 12:57:37 -0700969 if (extension.uri == ext_to_match.uri) {
970 if (!encryption_preference || extension.encrypt) {
jbauch5869f502017-06-29 12:31:36 -0700971 if (found_extension) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700972 *found_extension = extension;
jbauch5869f502017-06-29 12:31:36 -0700973 }
974 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 }
Steve Anton3a66edf2018-09-10 12:57:37 -0700976 unencrypted_extension = &extension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977 }
978 }
jbauch5869f502017-06-29 12:31:36 -0700979 if (unencrypted_extension) {
980 if (found_extension) {
981 *found_extension = *unencrypted_extension;
982 }
983 return true;
984 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 return false;
986}
987
zhihuang1c378ed2017-08-17 14:10:50 -0700988// Adds all extensions from |reference_extensions| to |offered_extensions| that
989// don't already exist in |offered_extensions| and ensure the IDs don't
990// collide. If an extension is added, it's also added to |regular_extensions| or
991// |encrypted_extensions|, and if the extension is in |regular_extensions| or
992// |encrypted_extensions|, its ID is marked as used in |used_ids|.
993// |offered_extensions| is for either audio or video while |regular_extensions|
994// and |encrypted_extensions| are used for both audio and video. There could be
995// overlap between audio extensions and video extensions.
996static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
997 RtpHeaderExtensions* offered_extensions,
998 RtpHeaderExtensions* regular_extensions,
999 RtpHeaderExtensions* encrypted_extensions,
1000 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001001 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001002 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1003 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001004 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001005 if (reference_extension.encrypt) {
1006 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1007 &existing)) {
1008 offered_extensions->push_back(existing);
1009 } else {
1010 used_ids->FindAndSetIdUsed(&reference_extension);
1011 encrypted_extensions->push_back(reference_extension);
1012 offered_extensions->push_back(reference_extension);
1013 }
olka3c747662017-08-17 06:50:32 -07001014 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001015 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1016 &existing)) {
1017 offered_extensions->push_back(existing);
1018 } else {
1019 used_ids->FindAndSetIdUsed(&reference_extension);
1020 regular_extensions->push_back(reference_extension);
1021 offered_extensions->push_back(reference_extension);
1022 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001023 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 }
1025 }
1026}
1027
jbauch5869f502017-06-29 12:31:36 -07001028static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1029 RtpHeaderExtensions* all_extensions,
1030 UsedRtpHeaderExtensionIds* used_ids) {
1031 RtpHeaderExtensions encrypted_extensions;
1032 for (const webrtc::RtpExtension& extension : *extensions) {
1033 webrtc::RtpExtension existing;
1034 // Don't add encrypted extensions again that were already included in a
1035 // previous offer or regular extensions that are also included as encrypted
1036 // extensions.
1037 if (extension.encrypt ||
1038 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1039 (FindByUriWithEncryptionPreference(*extensions, extension, true,
Yves Gerey665174f2018-06-19 15:03:05 +02001040 &existing) &&
1041 existing.encrypt)) {
jbauch5869f502017-06-29 12:31:36 -07001042 continue;
1043 }
1044
1045 if (FindByUri(*all_extensions, extension, &existing)) {
1046 encrypted_extensions.push_back(existing);
1047 } else {
1048 webrtc::RtpExtension encrypted(extension);
1049 encrypted.encrypt = true;
1050 used_ids->FindAndSetIdUsed(&encrypted);
1051 all_extensions->push_back(encrypted);
1052 encrypted_extensions.push_back(encrypted);
1053 }
1054 }
1055 extensions->insert(extensions->end(), encrypted_extensions.begin(),
Yves Gerey665174f2018-06-19 15:03:05 +02001056 encrypted_extensions.end());
jbauch5869f502017-06-29 12:31:36 -07001057}
1058
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059static void NegotiateRtpHeaderExtensions(
1060 const RtpHeaderExtensions& local_extensions,
1061 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001062 bool enable_encrypted_rtp_header_extensions,
Johannes Kronce8e8672019-02-22 13:06:44 +01001063 RtpHeaderExtensions* negotiated_extensions) {
1064 // TransportSequenceNumberV2 is not offered by default. The special logic for
1065 // the TransportSequenceNumber extensions works as follows:
1066 // Offer Answer
1067 // V1 V1 if in local_extensions.
1068 // V1 and V2 V2 regardless of local_extensions.
1069 // V2 V2 regardless of local_extensions.
1070 const webrtc::RtpExtension* transport_sequence_number_v2_offer =
1071 webrtc::RtpExtension::FindHeaderExtensionByUri(
1072 offered_extensions,
1073 webrtc::RtpExtension::kTransportSequenceNumberV2Uri);
1074
Steve Anton3a66edf2018-09-10 12:57:37 -07001075 for (const webrtc::RtpExtension& ours : local_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001076 webrtc::RtpExtension theirs;
Yves Gerey665174f2018-06-19 15:03:05 +02001077 if (FindByUriWithEncryptionPreference(
Steve Anton3a66edf2018-09-10 12:57:37 -07001078 offered_extensions, ours, enable_encrypted_rtp_header_extensions,
Yves Gerey665174f2018-06-19 15:03:05 +02001079 &theirs)) {
Johannes Kronce8e8672019-02-22 13:06:44 +01001080 if (transport_sequence_number_v2_offer &&
1081 ours.uri == webrtc::RtpExtension::kTransportSequenceNumberUri) {
1082 // Don't respond to
1083 // http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
1084 // if we get an offer including
Johannes Kron8cc711a2019-03-07 22:36:35 +01001085 // http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02
Johannes Kronce8e8672019-02-22 13:06:44 +01001086 continue;
1087 } else {
1088 // We respond with their RTP header extension id.
1089 negotiated_extensions->push_back(theirs);
1090 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001091 }
1092 }
Johannes Kronce8e8672019-02-22 13:06:44 +01001093
1094 if (transport_sequence_number_v2_offer) {
1095 // Respond that we support kTransportSequenceNumberV2Uri.
1096 negotiated_extensions->push_back(*transport_sequence_number_v2_offer);
1097 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098}
1099
1100static void StripCNCodecs(AudioCodecs* audio_codecs) {
Steve Anton3a66edf2018-09-10 12:57:37 -07001101 audio_codecs->erase(std::remove_if(audio_codecs->begin(), audio_codecs->end(),
1102 [](const AudioCodec& codec) {
Niels Möller2edab4c2018-10-22 09:48:08 +02001103 return absl::EqualsIgnoreCase(
1104 codec.name, kComfortNoiseCodecName);
Steve Anton3a66edf2018-09-10 12:57:37 -07001105 }),
1106 audio_codecs->end());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001107}
1108
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001109template <class C>
1110static bool SetCodecsInAnswer(
1111 const MediaContentDescriptionImpl<C>* offer,
1112 const std::vector<C>& local_codecs,
1113 const MediaDescriptionOptions& media_description_options,
1114 const MediaSessionOptions& session_options,
1115 UniqueRandomIdGenerator* ssrc_generator,
1116 StreamParamsVec* current_streams,
1117 MediaContentDescriptionImpl<C>* answer) {
1118 std::vector<C> negotiated_codecs;
1119 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs,
1120 media_description_options.codec_preferences.empty());
1121 answer->AddCodecs(negotiated_codecs);
1122 answer->set_protocol(offer->protocol());
1123 if (!AddStreamParams(media_description_options.sender_options,
1124 session_options.rtcp_cname, ssrc_generator,
1125 current_streams, answer)) {
1126 return false; // Something went seriously wrong.
1127 }
1128 return true;
1129}
1130
zhihuang1c378ed2017-08-17 14:10:50 -07001131// Create a media content to be answered for the given |sender_options|
1132// according to the given session_options.rtcp_mux, session_options.streams,
1133// codecs, crypto, and current_streams. If we don't currently have crypto (in
1134// current_cryptos) and it is enabled (in secure_policy), crypto is created
1135// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1136// negotiated with the offer. If the negotiation fails, this method returns
1137// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138static bool CreateMediaContentAnswer(
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001139 const MediaContentDescription* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001140 const MediaDescriptionOptions& media_description_options,
1141 const MediaSessionOptions& session_options,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001142 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143 const CryptoParamsVec* current_cryptos,
1144 const RtpHeaderExtensions& local_rtp_extenstions,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001145 UniqueRandomIdGenerator* ssrc_generator,
jbauch5869f502017-06-29 12:31:36 -07001146 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 bool bundle_enabled,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001149 MediaContentDescription* answer) {
Johannes Kron9581bc42018-10-23 10:17:39 +02001150 answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151 RtpHeaderExtensions negotiated_rtp_extensions;
Yves Gerey665174f2018-06-19 15:03:05 +02001152 NegotiateRtpHeaderExtensions(
1153 local_rtp_extenstions, offer->rtp_header_extensions(),
1154 enable_encrypted_rtp_header_extensions, &negotiated_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1156
zhihuang1c378ed2017-08-17 14:10:50 -07001157 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001158 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1159 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1160 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001161
1162 if (sdes_policy != SEC_DISABLED) {
1163 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001164 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1165 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001166 if (current_cryptos) {
1167 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1168 }
1169 answer->AddCrypto(crypto);
1170 }
1171 }
1172
deadbeef7af91dd2016-12-13 11:29:11 -08001173 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 return false;
1175 }
1176
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001177 AddSimulcastToMediaDescription(media_description_options, answer);
1178
Steve Anton4e70a722017-11-28 14:57:10 -08001179 answer->set_direction(NegotiateRtpTransceiverDirection(
1180 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 return true;
1182}
1183
1184static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001185 const std::string& protocol,
1186 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001187 // Since not all applications serialize and deserialize the media protocol,
1188 // we will have to accept |protocol| to be empty.
1189 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 return true;
1191 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001192
zhihuangcf5b37c2016-05-05 11:44:35 -07001193 if (type == MEDIA_TYPE_DATA) {
1194 // Check for SCTP, but also for RTP for RTP-based data channels.
1195 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1196 if (secure_transport) {
1197 // Most likely scenarios first.
1198 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1199 IsPlainRtp(protocol);
1200 } else {
1201 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1202 }
1203 }
1204
1205 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1206 // JSEP specifies.
1207 if (secure_transport) {
1208 // Most likely scenarios first.
1209 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1210 } else {
1211 return IsPlainRtp(protocol);
1212 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213}
1214
1215static void SetMediaProtocol(bool secure_transport,
1216 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001217 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001219 else if (secure_transport)
1220 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 else
1222 desc->set_protocol(kMediaProtocolAvpf);
1223}
1224
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001225// Gets the TransportInfo of the given |content_name| from the
1226// |current_description|. If doesn't exist, returns a new one.
1227static const TransportDescription* GetTransportDescription(
1228 const std::string& content_name,
1229 const SessionDescription* current_description) {
1230 const TransportDescription* desc = NULL;
1231 if (current_description) {
1232 const TransportInfo* info =
1233 current_description->GetTransportInfoByName(content_name);
1234 if (info) {
1235 desc = &info->description;
1236 }
1237 }
1238 return desc;
1239}
1240
1241// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001242static bool IsDtlsActive(const ContentInfo* content,
1243 const SessionDescription* current_description) {
1244 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001245 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001246 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001247
zhihuang1c378ed2017-08-17 14:10:50 -07001248 size_t msection_index = content - &current_description->contents()[0];
1249
1250 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001251 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001252 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001253
zhihuang1c378ed2017-08-17 14:10:50 -07001254 return current_description->transport_infos()[msection_index]
1255 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001256}
1257
Steve Anton8ffb9c32017-08-31 15:45:38 -07001258void MediaDescriptionOptions::AddAudioSender(
1259 const std::string& track_id,
1260 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001261 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001262 AddSenderInternal(track_id, stream_ids, {}, SimulcastLayerList(), 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001263}
1264
Steve Anton8ffb9c32017-08-31 15:45:38 -07001265void MediaDescriptionOptions::AddVideoSender(
1266 const std::string& track_id,
1267 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001268 const std::vector<RidDescription>& rids,
1269 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001270 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001271 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001272 RTC_DCHECK(rids.empty() || num_sim_layers == 0)
1273 << "RIDs are the compliant way to indicate simulcast.";
1274 RTC_DCHECK(ValidateSimulcastLayers(rids, simulcast_layers));
1275 AddSenderInternal(track_id, stream_ids, rids, simulcast_layers,
1276 num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001277}
1278
zhihuang1c378ed2017-08-17 14:10:50 -07001279void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1280 const std::string& stream_id) {
1281 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001282 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1283 // than one stream?
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001284 AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285}
1286
Steve Anton8ffb9c32017-08-31 15:45:38 -07001287void MediaDescriptionOptions::AddSenderInternal(
1288 const std::string& track_id,
1289 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001290 const std::vector<RidDescription>& rids,
1291 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001292 int num_sim_layers) {
1293 // TODO(steveanton): Support any number of stream ids.
1294 RTC_CHECK(stream_ids.size() == 1U);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001295 SenderOptions options;
1296 options.track_id = track_id;
1297 options.stream_ids = stream_ids;
1298 options.simulcast_layers = simulcast_layers;
1299 options.rids = rids;
1300 options.num_sim_layers = num_sim_layers;
1301 sender_options.push_back(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302}
1303
zhihuang1c378ed2017-08-17 14:10:50 -07001304bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
Steve Anton64b626b2019-01-28 17:25:26 -08001305 return absl::c_any_of(
1306 media_description_options,
1307 [type](const MediaDescriptionOptions& t) { return t.type == type; });
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001308}
1309
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001311 const TransportDescriptionFactory* transport_desc_factory,
1312 rtc::UniqueRandomIdGenerator* ssrc_generator)
1313 : ssrc_generator_(ssrc_generator),
1314 transport_desc_factory_(transport_desc_factory) {
1315 RTC_DCHECK(ssrc_generator_);
1316}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317
1318MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1319 ChannelManager* channel_manager,
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08001320 const TransportDescriptionFactory* transport_desc_factory,
1321 rtc::UniqueRandomIdGenerator* ssrc_generator)
1322 : MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
ossudedfd282016-06-14 07:12:39 -07001323 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1324 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001326 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001328 channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001329 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001330}
1331
ossudedfd282016-06-14 07:12:39 -07001332const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1333 const {
ossu075af922016-06-14 03:29:38 -07001334 return audio_sendrecv_codecs_;
1335}
1336
1337const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1338 return audio_send_codecs_;
1339}
1340
1341const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1342 return audio_recv_codecs_;
1343}
1344
1345void MediaSessionDescriptionFactory::set_audio_codecs(
Yves Gerey665174f2018-06-19 15:03:05 +02001346 const AudioCodecs& send_codecs,
1347 const AudioCodecs& recv_codecs) {
ossu075af922016-06-14 03:29:38 -07001348 audio_send_codecs_ = send_codecs;
1349 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001350 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351}
1352
Amit Hilbuch77938e62018-12-21 09:23:38 -08001353static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
1354 RTC_DCHECK(extensions);
Elad Alon157540a2019-02-08 23:37:52 +01001355
1356 rtc::UniqueNumberGenerator<int> unique_id_generator;
1357 unique_id_generator.AddKnownId(0); // The first valid RTP extension ID is 1.
1358 for (const webrtc::RtpExtension& extension : *extensions) {
1359 const bool collision_free = unique_id_generator.AddKnownId(extension.id);
1360 RTC_DCHECK(collision_free);
1361 }
1362
Amit Hilbuch77938e62018-12-21 09:23:38 -08001363 // Unified Plan also offers the MID and RID header extensions.
Elad Alon157540a2019-02-08 23:37:52 +01001364 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kMidUri,
1365 unique_id_generator()));
1366 extensions->push_back(webrtc::RtpExtension(webrtc::RtpExtension::kRidUri,
1367 unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001368 extensions->push_back(webrtc::RtpExtension(
Elad Alon157540a2019-02-08 23:37:52 +01001369 webrtc::RtpExtension::kRepairedRidUri, unique_id_generator()));
Amit Hilbuch77938e62018-12-21 09:23:38 -08001370}
1371
1372RtpHeaderExtensions
1373MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
1374 RtpHeaderExtensions extensions = audio_rtp_extensions_;
1375 if (is_unified_plan_) {
1376 AddUnifiedPlanExtensions(&extensions);
1377 }
1378
1379 return extensions;
1380}
1381
1382RtpHeaderExtensions
1383MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
1384 RtpHeaderExtensions extensions = video_rtp_extensions_;
1385 if (is_unified_plan_) {
1386 AddUnifiedPlanExtensions(&extensions);
1387 }
1388
1389 return extensions;
1390}
1391
Steve Anton6fe1fba2018-12-11 10:15:23 -08001392std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001393 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394 const SessionDescription* current_description) const {
Steve Anton5c72e712018-12-10 14:25:30 -08001395 // Must have options for each existing section.
1396 if (current_description) {
1397 RTC_DCHECK_LE(current_description->contents().size(),
1398 session_options.media_description_options.size());
1399 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001400
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001401 IceCredentialsIterator ice_credentials(
1402 session_options.pooled_ice_credentials);
Steve Anton5c72e712018-12-10 14:25:30 -08001403
1404 std::vector<const ContentInfo*> current_active_contents;
1405 if (current_description) {
1406 current_active_contents =
1407 GetActiveContents(*current_description, session_options);
1408 }
1409
1410 StreamParamsVec current_streams =
1411 GetCurrentStreamParams(current_active_contents);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001412
zhihuang1c378ed2017-08-17 14:10:50 -07001413 AudioCodecs offer_audio_codecs;
1414 VideoCodecs offer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001415 RtpDataCodecs offer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001416 GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001417 &offer_video_codecs, &offer_rtp_data_codecs);
ossu075af922016-06-14 03:29:38 -07001418
zhihuang1c378ed2017-08-17 14:10:50 -07001419 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001421 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001422 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001423 FilterDataCodecs(&offer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001424 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001425
1426 RtpHeaderExtensions audio_rtp_extensions;
1427 RtpHeaderExtensions video_rtp_extensions;
Johannes Kron746dd0d2019-06-20 15:37:52 +02001428 GetRtpHdrExtsToOffer(current_active_contents,
1429 session_options.offer_extmap_allow_mixed,
1430 &audio_rtp_extensions, &video_rtp_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431
Steve Anton5c72e712018-12-10 14:25:30 -08001432 auto offer = absl::make_unique<SessionDescription>();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001433
zhihuang1c378ed2017-08-17 14:10:50 -07001434 // Iterate through the media description options, matching with existing media
1435 // descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001436 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001437 for (const MediaDescriptionOptions& media_description_options :
1438 session_options.media_description_options) {
1439 const ContentInfo* current_content = nullptr;
1440 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001441 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001442 current_content = &current_description->contents()[msection_index];
Steve Antondcc3c022017-12-22 16:02:54 -08001443 // Media type must match unless this media section is being recycled.
Steve Anton5c72e712018-12-10 14:25:30 -08001444 RTC_DCHECK(current_content->name != media_description_options.mid ||
Steve Antondcc3c022017-12-22 16:02:54 -08001445 IsMediaContentOfType(current_content,
zhihuang1c378ed2017-08-17 14:10:50 -07001446 media_description_options.type));
1447 }
1448 switch (media_description_options.type) {
1449 case MEDIA_TYPE_AUDIO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001450 if (!AddAudioContentForOffer(
1451 media_description_options, session_options, current_content,
1452 current_description, audio_rtp_extensions, offer_audio_codecs,
1453 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001454 return nullptr;
1455 }
1456 break;
1457 case MEDIA_TYPE_VIDEO:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001458 if (!AddVideoContentForOffer(
1459 media_description_options, session_options, current_content,
1460 current_description, video_rtp_extensions, offer_video_codecs,
1461 &current_streams, offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001462 return nullptr;
1463 }
1464 break;
1465 case MEDIA_TYPE_DATA:
1466 if (!AddDataContentForOffer(media_description_options, session_options,
1467 current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001468 offer_rtp_data_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001469 offer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001470 return nullptr;
1471 }
1472 break;
1473 default:
1474 RTC_NOTREACHED();
1475 }
1476 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001477 }
1478
1479 // Bundle the contents together, if we've been asked to do so, and update any
1480 // parameters that need to be tweaked for BUNDLE.
Steve Anton2bed3972019-01-04 17:04:30 -08001481 if (session_options.bundle_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001483 for (const ContentInfo& content : offer->contents()) {
Steve Anton2bed3972019-01-04 17:04:30 -08001484 if (content.rejected) {
1485 continue;
1486 }
zhihuang1c378ed2017-08-17 14:10:50 -07001487 // TODO(deadbeef): There are conditions that make bundling two media
1488 // descriptions together illegal. For example, they use the same payload
1489 // type to represent different codecs, or same IDs for different header
1490 // extensions. We need to detect this and not try to bundle those media
1491 // descriptions together.
1492 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001493 }
Steve Anton2bed3972019-01-04 17:04:30 -08001494 if (!offer_bundle.content_names().empty()) {
1495 offer->AddGroup(offer_bundle);
1496 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1497 RTC_LOG(LS_ERROR)
1498 << "CreateOffer failed to UpdateTransportInfoForBundle.";
1499 return nullptr;
1500 }
1501 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1502 RTC_LOG(LS_ERROR)
1503 << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1504 return nullptr;
1505 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506 }
1507 }
Steve Antone831b8c2018-02-01 12:22:16 -08001508
1509 // The following determines how to signal MSIDs to ensure compatibility with
1510 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001511 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001512 // Be conservative and signal using both a=msid and a=ssrc lines. Unified
1513 // Plan answerers will look at a=msid and Plan B answerers will look at the
1514 // a=ssrc MSID line.
1515 offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1516 cricket::kMsidSignalingSsrcAttribute);
1517 } else {
1518 // Plan B always signals MSID using a=ssrc lines.
1519 offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1520 }
1521
Johannes Kron89f874e2018-11-12 10:25:48 +01001522 offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
1523
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001524 if (session_options.media_transport_settings.has_value()) {
1525 offer->AddMediaTransportSetting(
1526 session_options.media_transport_settings->transport_name,
1527 session_options.media_transport_settings->transport_setting);
1528 }
1529
Steve Anton6fe1fba2018-12-11 10:15:23 -08001530 return offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001531}
1532
Steve Anton6fe1fba2018-12-11 10:15:23 -08001533std::unique_ptr<SessionDescription>
1534MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001535 const SessionDescription* offer,
1536 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001538 if (!offer) {
1539 return nullptr;
1540 }
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001541
Steve Anton5c72e712018-12-10 14:25:30 -08001542 // Must have options for exactly as many sections as in the offer.
1543 RTC_DCHECK_EQ(offer->contents().size(),
1544 session_options.media_description_options.size());
1545
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001546 IceCredentialsIterator ice_credentials(
1547 session_options.pooled_ice_credentials);
1548
Steve Anton5c72e712018-12-10 14:25:30 -08001549 std::vector<const ContentInfo*> current_active_contents;
1550 if (current_description) {
1551 current_active_contents =
1552 GetActiveContents(*current_description, session_options);
1553 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554
Steve Anton5c72e712018-12-10 14:25:30 -08001555 StreamParamsVec current_streams =
1556 GetCurrentStreamParams(current_active_contents);
Johannes Kron0854eb62018-10-10 22:33:20 +02001557
zhihuang1c378ed2017-08-17 14:10:50 -07001558 // Get list of all possible codecs that respects existing payload type
1559 // mappings and uses a single payload type space.
1560 //
1561 // Note that these lists may be further filtered for each m= section; this
1562 // step is done just to establish the payload type mappings shared by all
1563 // sections.
1564 AudioCodecs answer_audio_codecs;
1565 VideoCodecs answer_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001566 RtpDataCodecs answer_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001567 GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001568 &answer_video_codecs, &answer_rtp_data_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07001569
1570 if (!session_options.vad_enabled) {
1571 // If application doesn't want CN codecs in answer.
1572 StripCNCodecs(&answer_audio_codecs);
1573 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001574 FilterDataCodecs(&answer_rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001575 session_options.data_channel_type == DCT_SCTP);
1576
Steve Anton5c72e712018-12-10 14:25:30 -08001577 auto answer = absl::make_unique<SessionDescription>();
1578
1579 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1580 // group in the answer with the appropriate content names.
1581 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1582 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1583 // Transport info shared by the bundle group.
1584 std::unique_ptr<TransportInfo> bundle_transport;
1585
1586 answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
1587
zhihuang1c378ed2017-08-17 14:10:50 -07001588 // Iterate through the media description options, matching with existing
1589 // media descriptions in |current_description|.
Steve Antondcc3c022017-12-22 16:02:54 -08001590 size_t msection_index = 0;
zhihuang1c378ed2017-08-17 14:10:50 -07001591 for (const MediaDescriptionOptions& media_description_options :
1592 session_options.media_description_options) {
1593 const ContentInfo* offer_content = &offer->contents()[msection_index];
1594 // Media types and MIDs must match between the remote offer and the
1595 // MediaDescriptionOptions.
1596 RTC_DCHECK(
1597 IsMediaContentOfType(offer_content, media_description_options.type));
1598 RTC_DCHECK(media_description_options.mid == offer_content->name);
1599 const ContentInfo* current_content = nullptr;
1600 if (current_description &&
Steve Antondcc3c022017-12-22 16:02:54 -08001601 msection_index < current_description->contents().size()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001602 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001603 }
zhihuang1c378ed2017-08-17 14:10:50 -07001604 switch (media_description_options.type) {
1605 case MEDIA_TYPE_AUDIO:
1606 if (!AddAudioContentForAnswer(
1607 media_description_options, session_options, offer_content,
1608 offer, current_content, current_description,
1609 bundle_transport.get(), answer_audio_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001610 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001611 return nullptr;
1612 }
1613 break;
1614 case MEDIA_TYPE_VIDEO:
1615 if (!AddVideoContentForAnswer(
1616 media_description_options, session_options, offer_content,
1617 offer, current_content, current_description,
1618 bundle_transport.get(), answer_video_codecs, &current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001619 answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001620 return nullptr;
1621 }
1622 break;
1623 case MEDIA_TYPE_DATA:
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001624 if (!AddDataContentForAnswer(
1625 media_description_options, session_options, offer_content,
1626 offer, current_content, current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001627 bundle_transport.get(), answer_rtp_data_codecs,
1628 &current_streams, answer.get(), &ice_credentials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001629 return nullptr;
1630 }
1631 break;
1632 default:
1633 RTC_NOTREACHED();
1634 }
1635 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001636 // See if we can add the newly generated m= section to the BUNDLE group in
1637 // the answer.
1638 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001639 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001640 offer_bundle->HasContentName(added.name)) {
1641 answer_bundle.AddContentName(added.name);
1642 bundle_transport.reset(
1643 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001644 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 }
1646
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001647 // If a BUNDLE group was offered, put a BUNDLE group in the answer even if
1648 // it's empty. RFC5888 says:
1649 //
1650 // A SIP entity that receives an offer that contains an "a=group" line
1651 // with semantics that are understood MUST return an answer that
1652 // contains an "a=group" line with the same semantics.
1653 if (offer_bundle) {
deadbeefb7892532017-02-22 19:35:18 -08001654 answer->AddGroup(answer_bundle);
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001655 }
deadbeefb7892532017-02-22 19:35:18 -08001656
Taylor Brandstetter0ab56512018-04-12 10:30:48 -07001657 if (answer_bundle.FirstContentName()) {
deadbeefb7892532017-02-22 19:35:18 -08001658 // Share the same ICE credentials and crypto params across all contents,
1659 // as BUNDLE requires.
1660 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001661 RTC_LOG(LS_ERROR)
1662 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001663 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001664 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001665
deadbeefb7892532017-02-22 19:35:18 -08001666 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001667 RTC_LOG(LS_ERROR)
1668 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001669 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001670 }
1671 }
1672
Steve Antone831b8c2018-02-01 12:22:16 -08001673 // The following determines how to signal MSIDs to ensure compatibility with
1674 // older endpoints (in particular, older Plan B endpoints).
Steve Anton8f66ddb2018-12-10 16:08:05 -08001675 if (is_unified_plan_) {
Steve Antone831b8c2018-02-01 12:22:16 -08001676 // Unified Plan needs to look at what the offer included to find the most
1677 // compatible answer.
1678 if (offer->msid_signaling() == 0) {
1679 // We end up here in one of three cases:
1680 // 1. An empty offer. We'll reply with an empty answer so it doesn't
1681 // matter what we pick here.
1682 // 2. A data channel only offer. We won't add any MSIDs to the answer so
1683 // it also doesn't matter what we pick here.
1684 // 3. Media that's either sendonly or inactive from the remote endpoint.
1685 // We don't have any information to say whether the endpoint is Plan B
1686 // or Unified Plan, so be conservative and send both.
1687 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
1688 cricket::kMsidSignalingSsrcAttribute);
1689 } else if (offer->msid_signaling() ==
1690 (cricket::kMsidSignalingMediaSection |
1691 cricket::kMsidSignalingSsrcAttribute)) {
1692 // If both a=msid and a=ssrc MSID signaling methods were used, we're
1693 // probably talking to a Unified Plan endpoint so respond with just
1694 // a=msid.
1695 answer->set_msid_signaling(cricket::kMsidSignalingMediaSection);
1696 } else {
1697 // Otherwise, it's clear which method the offerer is using so repeat that
1698 // back to them.
1699 answer->set_msid_signaling(offer->msid_signaling());
1700 }
1701 } else {
1702 // Plan B always signals MSID using a=ssrc lines.
1703 answer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
1704 }
1705
Steve Anton6fe1fba2018-12-11 10:15:23 -08001706 return answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707}
1708
ossu075af922016-06-14 03:29:38 -07001709const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1710 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001711 switch (direction) {
1712 // If stream is inactive - generate list as if sendrecv.
1713 case RtpTransceiverDirection::kSendRecv:
1714 case RtpTransceiverDirection::kInactive:
1715 return audio_sendrecv_codecs_;
1716 case RtpTransceiverDirection::kSendOnly:
1717 return audio_send_codecs_;
1718 case RtpTransceiverDirection::kRecvOnly:
1719 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001720 }
Steve Anton1d03a752017-11-27 14:30:09 -08001721 RTC_NOTREACHED();
1722 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001723}
1724
1725const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1726 const RtpTransceiverDirection& offer,
1727 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001728 switch (answer) {
1729 // For inactive and sendrecv answers, generate lists as if we were to accept
1730 // the offer's direction. See RFC 3264 Section 6.1.
1731 case RtpTransceiverDirection::kSendRecv:
1732 case RtpTransceiverDirection::kInactive:
1733 return GetAudioCodecsForOffer(
1734 webrtc::RtpTransceiverDirectionReversed(offer));
1735 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001736 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001737 case RtpTransceiverDirection::kRecvOnly:
1738 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001739 }
Steve Anton1d03a752017-11-27 14:30:09 -08001740 RTC_NOTREACHED();
1741 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001742}
1743
Steve Anton5c72e712018-12-10 14:25:30 -08001744void MergeCodecsFromDescription(
1745 const std::vector<const ContentInfo*>& current_active_contents,
1746 AudioCodecs* audio_codecs,
1747 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001748 RtpDataCodecs* rtp_data_codecs,
Steve Anton5c72e712018-12-10 14:25:30 -08001749 UsedPayloadTypes* used_pltypes) {
1750 for (const ContentInfo* content : current_active_contents) {
1751 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001752 const AudioContentDescription* audio =
Steve Anton5c72e712018-12-10 14:25:30 -08001753 content->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001754 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001755 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001756 const VideoContentDescription* video =
Steve Anton5c72e712018-12-10 14:25:30 -08001757 content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001758 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
Steve Anton5c72e712018-12-10 14:25:30 -08001759 } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001760 const RtpDataContentDescription* data =
1761 content->media_description()->as_rtp_data();
1762 if (data) {
1763 // Only relevant for RTP datachannels
1764 MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
1765 used_pltypes);
1766 }
zhihuang1c378ed2017-08-17 14:10:50 -07001767 }
1768 }
1769}
1770
1771// Getting codecs for an offer involves these steps:
1772//
1773// 1. Construct payload type -> codec mappings for current description.
1774// 2. Add any reference codecs that weren't already present
1775// 3. For each individual media description (m= section), filter codecs based
1776// on the directional attribute (happens in another method).
1777void MediaSessionDescriptionFactory::GetCodecsForOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001778 const std::vector<const ContentInfo*>& current_active_contents,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779 AudioCodecs* audio_codecs,
1780 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001781 RtpDataCodecs* rtp_data_codecs) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001782 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001783 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1784 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001785 UsedPayloadTypes used_pltypes;
1786 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001787 video_codecs, rtp_data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788
Steve Anton5c72e712018-12-10 14:25:30 -08001789 // Add our codecs that are not in the current description.
zhihuang1c378ed2017-08-17 14:10:50 -07001790 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1791 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001792 MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001793}
1794
1795// Getting codecs for an answer involves these steps:
1796//
1797// 1. Construct payload type -> codec mappings for current description.
1798// 2. Add any codecs from the offer that weren't already present.
1799// 3. Add any remaining codecs that weren't already present.
1800// 4. For each individual media description (m= section), filter codecs based
1801// on the directional attribute (happens in another method).
1802void MediaSessionDescriptionFactory::GetCodecsForAnswer(
Steve Anton5c72e712018-12-10 14:25:30 -08001803 const std::vector<const ContentInfo*>& current_active_contents,
1804 const SessionDescription& remote_offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001805 AudioCodecs* audio_codecs,
1806 VideoCodecs* video_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001807 RtpDataCodecs* rtp_data_codecs) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001808 // First - get all codecs from the current description if the media type
1809 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1810 // new media type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001811 UsedPayloadTypes used_pltypes;
1812 MergeCodecsFromDescription(current_active_contents, audio_codecs,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001813 video_codecs, rtp_data_codecs, &used_pltypes);
zhihuang1c378ed2017-08-17 14:10:50 -07001814
1815 // Second - filter out codecs that we don't support at all and should ignore.
1816 AudioCodecs filtered_offered_audio_codecs;
1817 VideoCodecs filtered_offered_video_codecs;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001818 RtpDataCodecs filtered_offered_rtp_data_codecs;
Steve Anton5c72e712018-12-10 14:25:30 -08001819 for (const ContentInfo& content : remote_offer.contents()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001820 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1821 const AudioContentDescription* audio =
Steve Antonb1c1de12017-12-21 15:14:30 -08001822 content.media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07001823 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1824 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1825 filtered_offered_audio_codecs,
1826 offered_audio_codec, nullptr) &&
1827 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1828 offered_audio_codec, nullptr)) {
1829 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1830 }
1831 }
1832 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1833 const VideoContentDescription* video =
Steve Antonb1c1de12017-12-21 15:14:30 -08001834 content.media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07001835 for (const VideoCodec& offered_video_codec : video->codecs()) {
1836 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1837 filtered_offered_video_codecs,
1838 offered_video_codec, nullptr) &&
1839 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1840 offered_video_codec, nullptr)) {
1841 filtered_offered_video_codecs.push_back(offered_video_codec);
1842 }
1843 }
1844 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001845 const RtpDataContentDescription* data =
1846 content.media_description()->as_rtp_data();
1847 if (data) {
1848 // RTP data. This part is inactive for SCTP data.
1849 for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
1850 if (!FindMatchingCodec<RtpDataCodec>(
1851 data->codecs(), filtered_offered_rtp_data_codecs,
1852 offered_rtp_data_codec, nullptr) &&
1853 FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
1854 offered_rtp_data_codec,
1855 nullptr)) {
1856 filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
1857 }
zhihuang1c378ed2017-08-17 14:10:50 -07001858 }
1859 }
1860 }
1861 }
1862
Steve Anton5c72e712018-12-10 14:25:30 -08001863 // Add codecs that are not in the current description but were in
zhihuang1c378ed2017-08-17 14:10:50 -07001864 // |remote_offer|.
1865 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1866 &used_pltypes);
1867 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1868 &used_pltypes);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001869 MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
zhihuang1c378ed2017-08-17 14:10:50 -07001870 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871}
1872
1873void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
Steve Anton5c72e712018-12-10 14:25:30 -08001874 const std::vector<const ContentInfo*>& current_active_contents,
Johannes Kron746dd0d2019-06-20 15:37:52 +02001875 bool extmap_allow_mixed,
zhihuang1c378ed2017-08-17 14:10:50 -07001876 RtpHeaderExtensions* offer_audio_extensions,
1877 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001878 // All header extensions allocated from the same range to avoid potential
1879 // issues when using BUNDLE.
Johannes Kron746dd0d2019-06-20 15:37:52 +02001880
1881 // Strictly speaking the SDP attribute extmap_allow_mixed signals that the
1882 // receiver supports an RTP stream where one- and two-byte RTP header
1883 // extensions are mixed. For backwards compatibility reasons it's used in
1884 // WebRTC to signal that two-byte RTP header extensions are supported.
1885 UsedRtpHeaderExtensionIds used_ids(
1886 extmap_allow_mixed ? UsedRtpHeaderExtensionIds::IdDomain::kTwoByteAllowed
1887 : UsedRtpHeaderExtensionIds::IdDomain::kOneByteOnly);
jbauch5869f502017-06-29 12:31:36 -07001888 RtpHeaderExtensions all_regular_extensions;
1889 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890
1891 // First - get all extensions from the current description if the media type
1892 // is used.
1893 // Add them to |used_ids| so the local ids are not reused if a new media
1894 // type is added.
Steve Anton5c72e712018-12-10 14:25:30 -08001895 for (const ContentInfo* content : current_active_contents) {
1896 if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
1897 const AudioContentDescription* audio =
1898 content->media_description()->as_audio();
1899 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1900 &all_regular_extensions, &all_encrypted_extensions,
1901 &used_ids);
1902 } else if (IsMediaContentOfType(content, MEDIA_TYPE_VIDEO)) {
1903 const VideoContentDescription* video =
1904 content->media_description()->as_video();
1905 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1906 &all_regular_extensions, &all_encrypted_extensions,
1907 &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908 }
1909 }
1910
Steve Anton5c72e712018-12-10 14:25:30 -08001911 // Add our default RTP header extensions that are not in the current
1912 // description.
Steve Anton8f66ddb2018-12-10 16:08:05 -08001913 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1914 &all_regular_extensions, &all_encrypted_extensions,
1915 &used_ids);
1916 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1917 &all_regular_extensions, &all_encrypted_extensions,
1918 &used_ids);
zhihuang1c378ed2017-08-17 14:10:50 -07001919
jbauch5869f502017-06-29 12:31:36 -07001920 // TODO(jbauch): Support adding encrypted header extensions to existing
1921 // sessions.
Steve Anton5c72e712018-12-10 14:25:30 -08001922 if (enable_encrypted_rtp_header_extensions_ &&
1923 current_active_contents.empty()) {
zhihuang1c378ed2017-08-17 14:10:50 -07001924 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1925 &all_encrypted_extensions, &used_ids);
1926 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1927 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001928 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929}
1930
1931bool MediaSessionDescriptionFactory::AddTransportOffer(
Yves Gerey665174f2018-06-19 15:03:05 +02001932 const std::string& content_name,
1933 const TransportOptions& transport_options,
1934 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001935 SessionDescription* offer_desc,
1936 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937 if (!transport_desc_factory_)
Yves Gerey665174f2018-06-19 15:03:05 +02001938 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939 const TransportDescription* current_tdesc =
1940 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001941 std::unique_ptr<TransportDescription> new_tdesc(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001942 transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
1943 ice_credentials));
Steve Anton06817cd2018-12-18 15:55:30 -08001944 if (!new_tdesc) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001945 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1946 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001947 }
Steve Anton06817cd2018-12-18 15:55:30 -08001948 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc));
1949 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950}
1951
Steve Anton1a9d3c32018-12-10 17:18:54 -08001952std::unique_ptr<TransportDescription>
1953MediaSessionDescriptionFactory::CreateTransportAnswer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954 const std::string& content_name,
1955 const SessionDescription* offer_desc,
1956 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001957 const SessionDescription* current_desc,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001958 bool require_transport_attributes,
1959 IceCredentialsIterator* ice_credentials) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960 if (!transport_desc_factory_)
1961 return NULL;
1962 const TransportDescription* offer_tdesc =
1963 GetTransportDescription(content_name, offer_desc);
1964 const TransportDescription* current_tdesc =
1965 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001966 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1967 require_transport_attributes,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001968 current_tdesc, ice_credentials);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969}
1970
1971bool MediaSessionDescriptionFactory::AddTransportAnswer(
1972 const std::string& content_name,
1973 const TransportDescription& transport_desc,
1974 SessionDescription* answer_desc) const {
Steve Anton06817cd2018-12-18 15:55:30 -08001975 answer_desc->AddTransportInfo(TransportInfo(content_name, transport_desc));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976 return true;
1977}
1978
zhihuang1c378ed2017-08-17 14:10:50 -07001979// |audio_codecs| = set of all possible codecs that can be used, with correct
1980// payload type mappings
1981//
1982// |supported_audio_codecs| = set of codecs that are supported for the direction
1983// of this m= section
1984//
1985// acd->codecs() = set of previously negotiated codecs for this m= section
1986//
1987// The payload types should come from audio_codecs, but the order should come
1988// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1989// change existing codec priority, and that new codecs are added with the right
1990// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001991bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001992 const MediaDescriptionOptions& media_description_options,
1993 const MediaSessionOptions& session_options,
1994 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001995 const SessionDescription* current_description,
1996 const RtpHeaderExtensions& audio_rtp_extensions,
1997 const AudioCodecs& audio_codecs,
1998 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001999 SessionDescription* desc,
2000 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002001 // Filter audio_codecs (which includes all codecs, with correctly remapped
2002 // payload types) based on transceiver direction.
2003 const AudioCodecs& supported_audio_codecs =
2004 GetAudioCodecsForOffer(media_description_options.direction);
2005
2006 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002007
2008 if (!media_description_options.codec_preferences.empty()) {
2009 // Add the codecs from the current transceiver's codec preferences.
2010 // They override any existing codecs from previous negotiations.
2011 filtered_codecs = MatchCodecPreference(
2012 media_description_options.codec_preferences, supported_audio_codecs);
2013 } else {
2014 // Add the codecs from current content if it exists and is not rejected nor
2015 // recycled.
2016 if (current_content && !current_content->rejected &&
2017 current_content->name == media_description_options.mid) {
2018 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2019 const AudioContentDescription* acd =
2020 current_content->media_description()->as_audio();
2021 for (const AudioCodec& codec : acd->codecs()) {
2022 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2023 nullptr)) {
2024 filtered_codecs.push_back(codec);
2025 }
zhihuang1c378ed2017-08-17 14:10:50 -07002026 }
2027 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002028 // Add other supported audio codecs.
2029 AudioCodec found_codec;
2030 for (const AudioCodec& codec : supported_audio_codecs) {
2031 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2032 codec, &found_codec) &&
2033 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2034 filtered_codecs, codec, nullptr)) {
2035 // Use the |found_codec| from |audio_codecs| because it has the
2036 // correctly mapped payload type.
2037 filtered_codecs.push_back(found_codec);
2038 }
zhihuang1c378ed2017-08-17 14:10:50 -07002039 }
2040 }
deadbeef44f08192015-12-15 16:20:09 -08002041
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002043 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2044 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002045
kwiberg31022942016-03-11 14:18:21 -08002046 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002047 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002048 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
2049 &crypto_suites);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002050 if (!CreateMediaContentOffer(media_description_options, session_options,
2051 filtered_codecs, sdes_policy,
2052 GetCryptos(current_content), crypto_suites,
2053 audio_rtp_extensions, ssrc_generator_,
2054 current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002055 return false;
2056 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002057
2058 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2059 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00002060
Steve Anton4e70a722017-11-28 14:57:10 -08002061 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002062
Steve Anton5adfafd2017-12-20 16:34:00 -08002063 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002064 media_description_options.stopped, std::move(audio));
zhihuang1c378ed2017-08-17 14:10:50 -07002065 if (!AddTransportOffer(media_description_options.mid,
2066 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002067 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002068 return false;
2069 }
2070
2071 return true;
2072}
2073
2074bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002075 const MediaDescriptionOptions& media_description_options,
2076 const MediaSessionOptions& session_options,
2077 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002078 const SessionDescription* current_description,
2079 const RtpHeaderExtensions& video_rtp_extensions,
2080 const VideoCodecs& video_codecs,
2081 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002082 SessionDescription* desc,
2083 IceCredentialsIterator* ice_credentials) const {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002084 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002085 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2086 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002087
kwiberg31022942016-03-11 14:18:21 -08002088 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002089 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07002090 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
2091 &crypto_suites);
2092
2093 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002094
2095 if (!media_description_options.codec_preferences.empty()) {
2096 // Add the codecs from the current transceiver's codec preferences.
2097 // They override any existing codecs from previous negotiations.
2098 filtered_codecs = MatchCodecPreference(
2099 media_description_options.codec_preferences, video_codecs_);
2100 } else {
2101 // Add the codecs from current content if it exists and is not rejected nor
2102 // recycled.
2103 if (current_content && !current_content->rejected &&
2104 current_content->name == media_description_options.mid) {
2105 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2106 const VideoContentDescription* vcd =
2107 current_content->media_description()->as_video();
2108 for (const VideoCodec& codec : vcd->codecs()) {
2109 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2110 nullptr)) {
2111 filtered_codecs.push_back(codec);
2112 }
zhihuang1c378ed2017-08-17 14:10:50 -07002113 }
2114 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002115 // Add other supported video codecs.
2116 VideoCodec found_codec;
2117 for (const VideoCodec& codec : video_codecs_) {
2118 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2119 &found_codec) &&
2120 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2121 nullptr)) {
2122 // Use the |found_codec| from |video_codecs| because it has the
2123 // correctly mapped payload type.
2124 filtered_codecs.push_back(found_codec);
2125 }
zhihuang1c378ed2017-08-17 14:10:50 -07002126 }
2127 }
2128
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002129 if (session_options.raw_packetization_for_video) {
2130 for (VideoCodec& codec : filtered_codecs) {
2131 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2132 codec.packetization = kPacketizationParamRaw;
2133 }
2134 }
2135 }
2136
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002137 if (!CreateMediaContentOffer(media_description_options, session_options,
2138 filtered_codecs, sdes_policy,
2139 GetCryptos(current_content), crypto_suites,
2140 video_rtp_extensions, ssrc_generator_,
2141 current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002142 return false;
2143 }
2144
zhihuang1c378ed2017-08-17 14:10:50 -07002145 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002146
2147 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2148 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002149
Steve Anton4e70a722017-11-28 14:57:10 -08002150 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002151
Steve Anton5adfafd2017-12-20 16:34:00 -08002152 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002153 media_description_options.stopped, std::move(video));
zhihuang1c378ed2017-08-17 14:10:50 -07002154 if (!AddTransportOffer(media_description_options.mid,
2155 media_description_options.transport_options,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002156 current_description, desc, ice_credentials)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002157 return false;
2158 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002159 return true;
2160}
2161
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002162bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
2163 const MediaDescriptionOptions& media_description_options,
2164 const MediaSessionOptions& session_options,
2165 const ContentInfo* current_content,
2166 const SessionDescription* current_description,
2167 StreamParamsVec* current_streams,
2168 SessionDescription* desc,
2169 IceCredentialsIterator* ice_credentials) const {
2170 std::unique_ptr<SctpDataContentDescription> data(
2171 new SctpDataContentDescription());
2172
2173 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2174
2175 cricket::SecurePolicy sdes_policy =
2176 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2177 : secure();
2178 std::vector<std::string> crypto_suites;
2179 // SDES doesn't make sense for SCTP, so we disable it, and we only
2180 // get SDES crypto suites for RTP-based data channels.
2181 sdes_policy = cricket::SEC_DISABLED;
2182 // Unlike SetMediaProtocol below, we need to set the protocol
2183 // before we call CreateMediaContentOffer. Otherwise,
2184 // CreateMediaContentOffer won't know this is SCTP and will
2185 // generate SSRCs rather than SIDs.
Guido Urdanetacecf87f2019-05-31 10:17:38 +00002186 data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002187 : kMediaProtocolSctp);
Harald Alvestrand4aa11922019-05-14 22:00:01 +02002188 data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002189 data->set_max_message_size(kSctpSendBufferSize);
2190
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002191 if (!CreateContentOffer(media_description_options, session_options,
2192 sdes_policy, GetCryptos(current_content),
2193 crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
2194 current_streams, data.get())) {
2195 return false;
2196 }
2197
2198 desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002199 std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002200 if (!AddTransportOffer(media_description_options.mid,
2201 media_description_options.transport_options,
2202 current_description, desc, ice_credentials)) {
2203 return false;
2204 }
2205 return true;
2206}
2207
2208bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
2209 const MediaDescriptionOptions& media_description_options,
2210 const MediaSessionOptions& session_options,
2211 const ContentInfo* current_content,
2212 const SessionDescription* current_description,
2213 const RtpDataCodecs& rtp_data_codecs,
2214 StreamParamsVec* current_streams,
2215 SessionDescription* desc,
2216 IceCredentialsIterator* ice_credentials) const {
2217 std::unique_ptr<RtpDataContentDescription> data(
2218 new RtpDataContentDescription());
2219 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
2220
2221 cricket::SecurePolicy sdes_policy =
2222 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2223 : secure();
2224 std::vector<std::string> crypto_suites;
2225 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
2226 &crypto_suites);
2227 if (!CreateMediaContentOffer(media_description_options, session_options,
2228 rtp_data_codecs, sdes_policy,
2229 GetCryptos(current_content), crypto_suites,
2230 RtpHeaderExtensions(), ssrc_generator_,
2231 current_streams, data.get())) {
2232 return false;
2233 }
2234
2235 data->set_bandwidth(kDataMaxBandwidth);
2236 SetMediaProtocol(secure_transport, data.get());
2237 desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002238 media_description_options.stopped, std::move(data));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002239 if (!AddTransportOffer(media_description_options.mid,
2240 media_description_options.transport_options,
2241 current_description, desc, ice_credentials)) {
2242 return false;
2243 }
2244 return true;
2245}
2246
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002247bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002248 const MediaDescriptionOptions& media_description_options,
2249 const MediaSessionOptions& session_options,
2250 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002251 const SessionDescription* current_description,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002252 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002253 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002254 SessionDescription* desc,
2255 IceCredentialsIterator* ice_credentials) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002256 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
2257 // If the DataChannel type is not specified, use the DataChannel type in
2258 // the current description.
2259 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002260 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
Steve Antonb1c1de12017-12-21 15:14:30 -08002261 is_sctp = (current_content->media_description()->protocol() ==
2262 kMediaProtocolSctp);
zhihuang1c378ed2017-08-17 14:10:50 -07002263 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002264 if (is_sctp) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002265 return AddSctpDataContentForOffer(
2266 media_description_options, session_options, current_content,
2267 current_description, current_streams, desc, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002268 } else {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002269 return AddRtpDataContentForOffer(media_description_options, session_options,
2270 current_content, current_description,
2271 rtp_data_codecs, current_streams, desc,
2272 ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002274}
2275
zhihuang1c378ed2017-08-17 14:10:50 -07002276// |audio_codecs| = set of all possible codecs that can be used, with correct
2277// payload type mappings
2278//
2279// |supported_audio_codecs| = set of codecs that are supported for the direction
2280// of this m= section
2281//
2282// acd->codecs() = set of previously negotiated codecs for this m= section
2283//
2284// The payload types should come from audio_codecs, but the order should come
2285// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2286// change existing codec priority, and that new codecs are added with the right
2287// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002288bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002289 const MediaDescriptionOptions& media_description_options,
2290 const MediaSessionOptions& session_options,
2291 const ContentInfo* offer_content,
2292 const SessionDescription* offer_description,
2293 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002294 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002295 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002296 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002297 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002298 SessionDescription* answer,
2299 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002300 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002301 const AudioContentDescription* offer_audio_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002302 offer_content->media_description()->as_audio();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002303
Steve Anton1a9d3c32018-12-10 17:18:54 -08002304 std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002305 media_description_options.mid, offer_description,
2306 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002307 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002308 if (!audio_transport) {
2309 return false;
2310 }
2311
zhihuang1c378ed2017-08-17 14:10:50 -07002312 // Pick codecs based on the requested communications direction in the offer
2313 // and the selected direction in the answer.
2314 // Note these will be filtered one final time in CreateMediaContentAnswer.
2315 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002316 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002317 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002318 AudioCodecs supported_audio_codecs =
2319 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2320
2321 AudioCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002322
2323 if (!media_description_options.codec_preferences.empty()) {
2324 filtered_codecs = MatchCodecPreference(
2325 media_description_options.codec_preferences, supported_audio_codecs);
2326 } else {
2327 // Add the codecs from current content if it exists and is not rejected nor
2328 // recycled.
2329 if (current_content && !current_content->rejected &&
2330 current_content->name == media_description_options.mid) {
2331 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2332 const AudioContentDescription* acd =
2333 current_content->media_description()->as_audio();
2334 for (const AudioCodec& codec : acd->codecs()) {
2335 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2336 nullptr)) {
2337 filtered_codecs.push_back(codec);
2338 }
zhihuang1c378ed2017-08-17 14:10:50 -07002339 }
2340 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002341 // Add other supported audio codecs.
2342 for (const AudioCodec& codec : supported_audio_codecs) {
2343 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2344 codec, nullptr) &&
2345 !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
2346 filtered_codecs, codec, nullptr)) {
2347 // We should use the local codec with local parameters and the codec id
2348 // would be correctly mapped in |NegotiateCodecs|.
2349 filtered_codecs.push_back(codec);
2350 }
zhihuang1c378ed2017-08-17 14:10:50 -07002351 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002352 }
2353
zhihuang1c378ed2017-08-17 14:10:50 -07002354 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2355 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002356 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002357 new AudioContentDescription());
2358 // Do not require or create SDES cryptos if DTLS is used.
2359 cricket::SecurePolicy sdes_policy =
2360 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002361 if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
2362 media_description_options, session_options,
2363 ssrc_generator_, current_streams,
2364 audio_answer.get())) {
2365 return false;
2366 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002367 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002368 offer_audio_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002369 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002370 audio_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002371 enable_encrypted_rtp_header_extensions_, current_streams,
2372 bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002373 return false; // Fails the session setup.
2374 }
2375
deadbeefb7892532017-02-22 19:35:18 -08002376 bool secure = bundle_transport ? bundle_transport->description.secure()
2377 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002378 bool rejected = media_description_options.stopped ||
2379 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002380 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2381 audio_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002382 if (!AddTransportAnswer(media_description_options.mid,
2383 *(audio_transport.get()), answer)) {
2384 return false;
2385 }
2386
2387 if (rejected) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002388 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2389 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002390 }
2391
zhihuang1c378ed2017-08-17 14:10:50 -07002392 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002393 rejected, std::move(audio_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002394 return true;
2395}
2396
2397bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002398 const MediaDescriptionOptions& media_description_options,
2399 const MediaSessionOptions& session_options,
2400 const ContentInfo* offer_content,
2401 const SessionDescription* offer_description,
2402 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002403 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002404 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002405 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002406 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002407 SessionDescription* answer,
2408 IceCredentialsIterator* ice_credentials) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002409 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002410 const VideoContentDescription* offer_video_description =
Steve Antonb1c1de12017-12-21 15:14:30 -08002411 offer_content->media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07002412
Steve Anton1a9d3c32018-12-10 17:18:54 -08002413 std::unique_ptr<TransportDescription> video_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002414 media_description_options.mid, offer_description,
2415 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002416 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002417 if (!video_transport) {
2418 return false;
2419 }
2420
zhihuang1c378ed2017-08-17 14:10:50 -07002421 VideoCodecs filtered_codecs;
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002422
2423 if (!media_description_options.codec_preferences.empty()) {
2424 filtered_codecs = MatchCodecPreference(
2425 media_description_options.codec_preferences, video_codecs_);
2426 } else {
2427 // Add the codecs from current content if it exists and is not rejected nor
2428 // recycled.
2429 if (current_content && !current_content->rejected &&
2430 current_content->name == media_description_options.mid) {
2431 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2432 const VideoContentDescription* vcd =
2433 current_content->media_description()->as_video();
2434 for (const VideoCodec& codec : vcd->codecs()) {
2435 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
2436 nullptr)) {
2437 filtered_codecs.push_back(codec);
2438 }
zhihuang1c378ed2017-08-17 14:10:50 -07002439 }
2440 }
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002441 // Add other supported video codecs.
2442 for (const VideoCodec& codec : video_codecs_) {
2443 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2444 nullptr) &&
2445 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2446 nullptr)) {
2447 // We should use the local codec with local parameters and the codec id
2448 // would be correctly mapped in |NegotiateCodecs|.
2449 filtered_codecs.push_back(codec);
2450 }
zhihuang1c378ed2017-08-17 14:10:50 -07002451 }
2452 }
2453
Mirta Dvornicic479a3c02019-06-04 15:38:50 +02002454 if (session_options.raw_packetization_for_video) {
2455 for (VideoCodec& codec : filtered_codecs) {
2456 if (codec.GetCodecType() == VideoCodec::CODEC_VIDEO) {
2457 codec.packetization = kPacketizationParamRaw;
2458 }
2459 }
2460 }
2461
zhihuang1c378ed2017-08-17 14:10:50 -07002462 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2463 session_options.bundle_enabled;
2464
kwiberg31022942016-03-11 14:18:21 -08002465 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002466 new VideoContentDescription());
2467 // Do not require or create SDES cryptos if DTLS is used.
2468 cricket::SecurePolicy sdes_policy =
2469 video_transport->secure() ? cricket::SEC_DISABLED : secure();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002470 if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
2471 media_description_options, session_options,
2472 ssrc_generator_, current_streams,
2473 video_answer.get())) {
2474 return false;
2475 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002476 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002477 offer_video_description, media_description_options, session_options,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002478 sdes_policy, GetCryptos(current_content),
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08002479 video_rtp_header_extensions(), ssrc_generator_,
Steve Anton1b8773d2018-04-06 11:13:34 -07002480 enable_encrypted_rtp_header_extensions_, current_streams,
2481 bundle_enabled, video_answer.get())) {
zhihuang1c378ed2017-08-17 14:10:50 -07002482 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002483 }
deadbeefb7892532017-02-22 19:35:18 -08002484 bool secure = bundle_transport ? bundle_transport->description.secure()
2485 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002486 bool rejected = media_description_options.stopped ||
2487 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002488 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2489 video_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002490 if (!AddTransportAnswer(media_description_options.mid,
2491 *(video_transport.get()), answer)) {
2492 return false;
2493 }
2494
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002495 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002496 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002497 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002498 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2499 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002500 }
zhihuang1c378ed2017-08-17 14:10:50 -07002501 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002502 rejected, std::move(video_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002503 return true;
2504}
2505
2506bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002507 const MediaDescriptionOptions& media_description_options,
2508 const MediaSessionOptions& session_options,
2509 const ContentInfo* offer_content,
2510 const SessionDescription* offer_description,
2511 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002512 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002513 const TransportInfo* bundle_transport,
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002514 const RtpDataCodecs& rtp_data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002515 StreamParamsVec* current_streams,
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002516 SessionDescription* answer,
2517 IceCredentialsIterator* ice_credentials) const {
Steve Anton1a9d3c32018-12-10 17:18:54 -08002518 std::unique_ptr<TransportDescription> data_transport = CreateTransportAnswer(
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02002519 media_description_options.mid, offer_description,
2520 media_description_options.transport_options, current_description,
Steve Anton1a9d3c32018-12-10 17:18:54 -08002521 bundle_transport != nullptr, ice_credentials);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002522 if (!data_transport) {
2523 return false;
2524 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002525
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002526 // Do not require or create SDES cryptos if DTLS is used.
2527 cricket::SecurePolicy sdes_policy =
2528 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002529 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2530 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002531 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002532 std::unique_ptr<MediaContentDescription> data_answer;
2533 if (offer_content->media_description()->as_sctp()) {
2534 // SCTP data content
2535 data_answer = absl::make_unique<SctpDataContentDescription>();
2536 const SctpDataContentDescription* offer_data_description =
2537 offer_content->media_description()->as_sctp();
2538 // Respond with the offerer's proto, whatever it is.
2539 data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +02002540 // Respond with our max message size or the remote max messsage size,
2541 // whichever is smaller.
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02002542 // 0 is treated specially - it means "I can accept any size". Since
2543 // we do not implement infinite size messages, reply with
2544 // kSctpSendBufferSize.
2545 if (offer_data_description->max_message_size() == 0) {
2546 data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
2547 } else {
2548 data_answer->as_sctp()->set_max_message_size(std::min(
2549 offer_data_description->max_message_size(), kSctpSendBufferSize));
2550 }
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002551 if (!CreateMediaContentAnswer(
2552 offer_data_description, media_description_options, session_options,
2553 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2554 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2555 current_streams, bundle_enabled, data_answer.get())) {
2556 return false; // Fails the session setup.
2557 }
2558 // Respond with sctpmap if the offer uses sctpmap.
2559 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2560 data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
2561 } else {
2562 // RTP offer
2563 data_answer = absl::make_unique<RtpDataContentDescription>();
Harald Alvestrand141c0ad2019-05-05 19:00:00 +00002564
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002565 const RtpDataContentDescription* offer_data_description =
2566 offer_content->media_description()->as_rtp_data();
2567 RTC_CHECK(offer_data_description);
2568 if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
2569 media_description_options, session_options,
2570 ssrc_generator_, current_streams,
2571 data_answer->as_rtp_data())) {
2572 return false;
2573 }
2574 if (!CreateMediaContentAnswer(
2575 offer_data_description, media_description_options, session_options,
2576 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
2577 ssrc_generator_, enable_encrypted_rtp_header_extensions_,
2578 current_streams, bundle_enabled, data_answer.get())) {
2579 return false; // Fails the session setup.
2580 }
2581 }
Steve Anton46afbf92019-05-10 11:15:18 -07002582
deadbeefb7892532017-02-22 19:35:18 -08002583 bool secure = bundle_transport ? bundle_transport->description.secure()
2584 : data_transport->secure();
2585
zhihuang1c378ed2017-08-17 14:10:50 -07002586 bool rejected = session_options.data_channel_type == DCT_NONE ||
2587 media_description_options.stopped ||
2588 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002589 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2590 data_answer->protocol(), secure);
Zhi Huang3518e7b2018-01-30 13:20:35 -08002591 if (!AddTransportAnswer(media_description_options.mid,
2592 *(data_transport.get()), answer)) {
2593 return false;
2594 }
2595
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002596 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002597 data_answer->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002598 } else {
2599 // RFC 3264
2600 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002601 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002602 }
zhihuang1c378ed2017-08-17 14:10:50 -07002603 answer->AddContent(media_description_options.mid, offer_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02002604 rejected, std::move(data_answer));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002605 return true;
2606}
2607
zhihuang1c378ed2017-08-17 14:10:50 -07002608void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2609 audio_sendrecv_codecs_.clear();
2610 all_audio_codecs_.clear();
2611 // Compute the audio codecs union.
2612 for (const AudioCodec& send : audio_send_codecs_) {
2613 all_audio_codecs_.push_back(send);
2614 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2615 send, nullptr)) {
2616 // It doesn't make sense to have an RTX codec we support sending but not
2617 // receiving.
2618 RTC_DCHECK(!IsRtxCodec(send));
2619 }
2620 }
2621 for (const AudioCodec& recv : audio_recv_codecs_) {
2622 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2623 recv, nullptr)) {
2624 all_audio_codecs_.push_back(recv);
2625 }
2626 }
2627 // Use NegotiateCodecs to merge our codec lists, since the operation is
2628 // essentially the same. Put send_codecs as the offered_codecs, which is the
2629 // order we'd like to follow. The reasoning is that encoding is usually more
2630 // expensive than decoding, and prioritizing a codec in the send list probably
2631 // means it's a codec we can handle efficiently.
2632 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002633 &audio_sendrecv_codecs_, true);
zhihuang1c378ed2017-08-17 14:10:50 -07002634}
2635
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636bool IsMediaContent(const ContentInfo* content) {
Steve Anton5adfafd2017-12-20 16:34:00 -08002637 return (content && (content->type == MediaProtocolType::kRtp ||
2638 content->type == MediaProtocolType::kSctp));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639}
2640
2641bool IsAudioContent(const ContentInfo* content) {
2642 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2643}
2644
2645bool IsVideoContent(const ContentInfo* content) {
2646 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2647}
2648
2649bool IsDataContent(const ContentInfo* content) {
2650 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2651}
2652
deadbeef0ed85b22016-02-23 17:24:52 -08002653const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2654 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002655 for (const ContentInfo& content : contents) {
2656 if (IsMediaContentOfType(&content, media_type)) {
2657 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002658 }
2659 }
deadbeef0ed85b22016-02-23 17:24:52 -08002660 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661}
2662
2663const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2664 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2665}
2666
2667const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2668 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2669}
2670
2671const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2672 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2673}
2674
Steve Antonad7bffc2018-01-22 10:21:56 -08002675const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2676 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002677 if (sdesc == nullptr) {
2678 return nullptr;
2679 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680
2681 return GetFirstMediaContent(sdesc->contents(), media_type);
2682}
2683
2684const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2685 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2686}
2687
2688const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2689 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2690}
2691
2692const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2693 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2694}
2695
2696const MediaContentDescription* GetFirstMediaContentDescription(
Yves Gerey665174f2018-06-19 15:03:05 +02002697 const SessionDescription* sdesc,
2698 MediaType media_type) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002700 return (content ? content->media_description() : nullptr);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701}
2702
2703const AudioContentDescription* GetFirstAudioContentDescription(
2704 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002705 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2706 return desc ? desc->as_audio() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707}
2708
2709const VideoContentDescription* GetFirstVideoContentDescription(
2710 const SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002711 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2712 return desc ? desc->as_video() : nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713}
2714
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002715const RtpDataContentDescription* GetFirstRtpDataContentDescription(
2716 const SessionDescription* sdesc) {
2717 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2718 return desc ? desc->as_rtp_data() : nullptr;
2719}
2720
2721const SctpDataContentDescription* GetFirstSctpDataContentDescription(
2722 const SessionDescription* sdesc) {
2723 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2724 return desc ? desc->as_sctp() : nullptr;
2725}
2726
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002727//
2728// Non-const versions of the above functions.
2729//
2730
Steve Anton36b29d12017-10-30 09:57:42 -07002731ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002732 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002733 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002734 if (IsMediaContentOfType(&content, media_type)) {
2735 return &content;
2736 }
2737 }
2738 return nullptr;
2739}
2740
Steve Anton36b29d12017-10-30 09:57:42 -07002741ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002742 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2743}
2744
Steve Anton36b29d12017-10-30 09:57:42 -07002745ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002746 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2747}
2748
Steve Anton36b29d12017-10-30 09:57:42 -07002749ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002750 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2751}
2752
Steve Antonad7bffc2018-01-22 10:21:56 -08002753ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2754 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002755 if (sdesc == nullptr) {
2756 return nullptr;
2757 }
2758
Steve Anton36b29d12017-10-30 09:57:42 -07002759 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002760}
2761
2762ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2763 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2764}
2765
2766ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2767 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2768}
2769
2770ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2771 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2772}
2773
2774MediaContentDescription* GetFirstMediaContentDescription(
2775 SessionDescription* sdesc,
2776 MediaType media_type) {
2777 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002778 return (content ? content->media_description() : nullptr);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002779}
2780
2781AudioContentDescription* GetFirstAudioContentDescription(
2782 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002783 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
2784 return desc ? desc->as_audio() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002785}
2786
2787VideoContentDescription* GetFirstVideoContentDescription(
2788 SessionDescription* sdesc) {
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002789 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
2790 return desc ? desc->as_video() : nullptr;
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002791}
2792
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002793RtpDataContentDescription* GetFirstRtpDataContentDescription(
2794 SessionDescription* sdesc) {
2795 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2796 return desc ? desc->as_rtp_data() : nullptr;
2797}
2798
2799SctpDataContentDescription* GetFirstSctpDataContentDescription(
2800 SessionDescription* sdesc) {
2801 auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
2802 return desc ? desc->as_sctp() : nullptr;
2803}
2804
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805} // namespace cricket