blob: 0818f3ba91e5e0005aea2b7a4ef16f4e362d51e3 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeef67cf2c12016-04-13 10:07:16 -070013#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Patrik Höglund7aee3d52017-11-15 13:15:17 +010021#include "api/cryptoparams.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "api/optional.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020023#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "media/base/h264_profile_level_id.h"
25#include "media/base/mediaconstants.h"
26#include "p2p/base/p2pconstants.h"
27#include "pc/channelmanager.h"
Steve Anton1d03a752017-11-27 14:30:09 -080028#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "pc/srtpfilter.h"
30#include "rtc_base/base64.h"
31#include "rtc_base/checks.h"
32#include "rtc_base/helpers.h"
33#include "rtc_base/logging.h"
34#include "rtc_base/stringutils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
36namespace {
Steve Anton1d03a752017-11-27 14:30:09 -080037
38using webrtc::RtpTransceiverDirection;
39
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080041
deadbeef7914b8c2017-04-21 03:23:33 -070042void GetSupportedSdesCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
43 std::vector<int>*),
44 const rtc::CryptoOptions& crypto_options,
45 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080046 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070047 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080048 for (const auto crypto : crypto_suites) {
49 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
50 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080051}
terelius8c011e52016-04-26 05:28:11 -070052} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053
54namespace cricket {
55
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056// RTP Profile names
57// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
58// RFC4585
59const char kMediaProtocolAvpf[] = "RTP/AVPF";
60// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000061const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
62
deadbeeff3938292015-07-15 12:20:53 -070063// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
64// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065const char kMediaProtocolSavpf[] = "RTP/SAVPF";
66
67const char kMediaProtocolRtpPrefix[] = "RTP/";
68
69const char kMediaProtocolSctp[] = "SCTP";
70const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000071const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000072const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
deadbeef8b7e9ad2017-05-25 09:38:55 -070074// Note that the below functions support some protocol strings purely for
75// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
76// and Interoperability.
77
78static bool IsDtlsRtp(const std::string& protocol) {
79 // Most-likely values first.
80 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
81 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
82}
83
84static bool IsPlainRtp(const std::string& protocol) {
85 // Most-likely values first.
86 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
87 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
88}
89
90static bool IsDtlsSctp(const std::string& protocol) {
91 return protocol == kMediaProtocolDtlsSctp ||
92 protocol == kMediaProtocolUdpDtlsSctp ||
93 protocol == kMediaProtocolTcpDtlsSctp;
94}
95
96static bool IsPlainSctp(const std::string& protocol) {
97 return protocol == kMediaProtocolSctp;
98}
99
100static bool IsSctp(const std::string& protocol) {
101 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
102}
103
Steve Anton1d03a752017-11-27 14:30:09 -0800104static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
105 RtpTransceiverDirection offer,
106 RtpTransceiverDirection wants) {
107 bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
108 bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
109 bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
110 bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
111 return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
112 offer_send && wants_recv);
ossu075af922016-06-14 03:29:38 -0700113}
114
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115static bool IsMediaContentOfType(const ContentInfo* content,
116 MediaType media_type) {
117 if (!IsMediaContent(content)) {
118 return false;
119 }
120
121 const MediaContentDescription* mdesc =
122 static_cast<const MediaContentDescription*>(content->description);
123 return mdesc && mdesc->type() == media_type;
124}
125
126static bool CreateCryptoParams(int tag, const std::string& cipher,
127 CryptoParams *out) {
jbauchcb560652016-08-04 05:20:32 -0700128 int key_len;
129 int salt_len;
130 if (!rtc::GetSrtpKeyAndSaltLengths(
131 rtc::SrtpCryptoSuiteFromName(cipher), &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132 return false;
133 }
jbauchcb560652016-08-04 05:20:32 -0700134
135 int master_key_len = key_len + salt_len;
136 std::string master_key;
137 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
138 return false;
139 }
140
kwiberg352444f2016-11-28 15:58:53 -0800141 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700142 std::string key = rtc::Base64::Encode(master_key);
143
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144 out->tag = tag;
145 out->cipher_suite = cipher;
146 out->key_params = kInline;
147 out->key_params += key;
148 return true;
149}
150
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151static bool AddCryptoParams(const std::string& cipher_suite,
152 CryptoParamsVec *out) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000153 int size = static_cast<int>(out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154
155 out->resize(size + 1);
156 return CreateCryptoParams(size, cipher_suite, &out->at(size));
157}
158
159void AddMediaCryptos(const CryptoParamsVec& cryptos,
160 MediaContentDescription* media) {
161 for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
162 crypto != cryptos.end(); ++crypto) {
163 media->AddCrypto(*crypto);
164 }
165}
166
167bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
168 MediaContentDescription* media) {
169 CryptoParamsVec cryptos;
170 for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
171 it != crypto_suites.end(); ++it) {
172 if (!AddCryptoParams(*it, &cryptos)) {
173 return false;
174 }
175 }
176 AddMediaCryptos(cryptos, media);
177 return true;
178}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179
zhihuang1c378ed2017-08-17 14:10:50 -0700180const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
181 if (!content) {
182 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183 }
zhihuang1c378ed2017-08-17 14:10:50 -0700184
185 RTC_DCHECK(IsMediaContent(content));
186 return &(static_cast<const MediaContentDescription*>(content->description)
187 ->cryptos());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188}
189
190bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
191 const CryptoParams& crypto,
192 CryptoParams* out) {
193 for (CryptoParamsVec::const_iterator it = cryptos.begin();
194 it != cryptos.end(); ++it) {
195 if (crypto.Matches(*it)) {
196 *out = *it;
197 return true;
198 }
199 }
200 return false;
201}
202
jbauchcb560652016-08-04 05:20:32 -0700203// For audio, HMAC 32 is prefered over HMAC 80 because of the low overhead.
deadbeef7914b8c2017-04-21 03:23:33 -0700204void GetSupportedAudioSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
205 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700206 if (crypto_options.enable_gcm_crypto_suites) {
207 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_32);
211 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212}
213
deadbeef7914b8c2017-04-21 03:23:33 -0700214void GetSupportedAudioSdesCryptoSuiteNames(
215 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800216 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700217 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
218 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219}
220
deadbeef7914b8c2017-04-21 03:23:33 -0700221void GetSupportedVideoSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
222 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700223 if (crypto_options.enable_gcm_crypto_suites) {
224 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
225 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
226 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800227 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228}
229
deadbeef7914b8c2017-04-21 03:23:33 -0700230void GetSupportedVideoSdesCryptoSuiteNames(
231 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800232 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700233 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
234 crypto_options, crypto_suite_names);
235}
236
237void GetSupportedDataSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
238 std::vector<int>* crypto_suites) {
239 if (crypto_options.enable_gcm_crypto_suites) {
240 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
241 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
242 }
243 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
244}
245
246void GetSupportedDataSdesCryptoSuiteNames(
247 const rtc::CryptoOptions& crypto_options,
248 std::vector<std::string>* crypto_suite_names) {
249 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
250 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800251}
252
jbauchcb560652016-08-04 05:20:32 -0700253// Support any GCM cipher (if enabled through options). For video support only
254// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated unless bundle is enabled
255// because it is low overhead.
256// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257static bool SelectCrypto(const MediaContentDescription* offer,
258 bool bundle,
jbauchcb560652016-08-04 05:20:32 -0700259 const rtc::CryptoOptions& crypto_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 CryptoParams *crypto) {
261 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
262 const CryptoParamsVec& cryptos = offer->cryptos();
263
264 for (CryptoParamsVec::const_iterator i = cryptos.begin();
265 i != cryptos.end(); ++i) {
jbauchcb560652016-08-04 05:20:32 -0700266 if ((crypto_options.enable_gcm_crypto_suites &&
267 rtc::IsGcmCryptoSuiteName(i->cipher_suite)) ||
268 rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
Guo-wei Shieh456696a2015-09-30 21:48:54 -0700269 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
270 !bundle)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
272 }
273 }
274 return false;
275}
276
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000277// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000278// The generated values are added to |ssrcs|.
279// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000281 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200282 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000283 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200284 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000286 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000287 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
289 ssrcs->push_back(candidate);
290 }
291}
292
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293// Finds all StreamParams of all media types and attach them to stream_params.
294static void GetCurrentStreamParams(const SessionDescription* sdesc,
295 StreamParamsVec* stream_params) {
296 if (!sdesc)
297 return;
298
299 const ContentInfos& contents = sdesc->contents();
300 for (ContentInfos::const_iterator content = contents.begin();
301 content != contents.end(); ++content) {
302 if (!IsMediaContent(&*content)) {
303 continue;
304 }
305 const MediaContentDescription* media =
306 static_cast<const MediaContentDescription*>(
307 content->description);
308 const StreamParamsVec& streams = media->streams();
309 for (StreamParamsVec::const_iterator it = streams.begin();
310 it != streams.end(); ++it) {
311 stream_params->push_back(*it);
312 }
313 }
314}
315
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000316// Filters the data codecs for the data channel type.
317void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
318 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700319 const char* codec_name =
320 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000321 for (std::vector<DataCodec>::iterator iter = codecs->begin();
322 iter != codecs->end();) {
solenberg9fa49752016-10-08 13:02:44 -0700323 if (CodecNamesEq(iter->name, codec_name)) {
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000324 iter = codecs->erase(iter);
325 } else {
326 ++iter;
327 }
328 }
329}
330
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331template <typename IdStruct>
332class UsedIds {
333 public:
334 UsedIds(int min_allowed_id, int max_allowed_id)
335 : min_allowed_id_(min_allowed_id),
336 max_allowed_id_(max_allowed_id),
337 next_id_(max_allowed_id) {
338 }
339
340 // Loops through all Id in |ids| and changes its id if it is
341 // already in use by another IdStruct. Call this methods with all Id
342 // in a session description to make sure no duplicate ids exists.
343 // Note that typename Id must be a type of IdStruct.
344 template <typename Id>
345 void FindAndSetIdUsed(std::vector<Id>* ids) {
346 for (typename std::vector<Id>::iterator it = ids->begin();
347 it != ids->end(); ++it) {
348 FindAndSetIdUsed(&*it);
349 }
350 }
351
352 // Finds and sets an unused id if the |idstruct| id is already in use.
353 void FindAndSetIdUsed(IdStruct* idstruct) {
354 const int original_id = idstruct->id;
355 int new_id = idstruct->id;
356
357 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
358 // If the original id is not in range - this is an id that can't be
359 // dynamically changed.
360 return;
361 }
362
363 if (IsIdUsed(original_id)) {
364 new_id = FindUnusedId();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100365 RTC_LOG(LS_WARNING) << "Duplicate id found. Reassigning from "
366 << original_id << " to " << new_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 idstruct->id = new_id;
368 }
369 SetIdUsed(new_id);
370 }
371
372 private:
373 // Returns the first unused id in reverse order.
374 // This hopefully reduce the risk of more collisions. We want to change the
375 // default ids as little as possible.
376 int FindUnusedId() {
377 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
378 --next_id_;
379 }
nisseede5da42017-01-12 05:15:36 -0800380 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000381 return next_id_;
382 }
383
384 bool IsIdUsed(int new_id) {
385 return id_set_.find(new_id) != id_set_.end();
386 }
387
388 void SetIdUsed(int new_id) {
389 id_set_.insert(new_id);
390 }
391
392 const int min_allowed_id_;
393 const int max_allowed_id_;
394 int next_id_;
395 std::set<int> id_set_;
396};
397
398// Helper class used for finding duplicate RTP payload types among audio, video
399// and data codecs. When bundle is used the payload types may not collide.
400class UsedPayloadTypes : public UsedIds<Codec> {
401 public:
402 UsedPayloadTypes()
403 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
404 }
405
406
407 private:
408 static const int kDynamicPayloadTypeMin = 96;
409 static const int kDynamicPayloadTypeMax = 127;
410};
411
412// Helper class used for finding duplicate RTP Header extension ids among
413// audio and video extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700414class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 public:
416 UsedRtpHeaderExtensionIds()
deadbeefe814a0d2017-02-25 18:15:09 -0800417 : UsedIds<webrtc::RtpExtension>(webrtc::RtpExtension::kMinId,
418 webrtc::RtpExtension::kMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419
420 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421};
422
zhihuang1c378ed2017-08-17 14:10:50 -0700423// Adds a StreamParams for each SenderOptions in |sender_options| to
424// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425// |current_params| - All currently known StreamParams of any media type.
426template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700427static bool AddStreamParams(
428 const std::vector<SenderOptions>& sender_options,
429 const std::string& rtcp_cname,
430 StreamParamsVec* current_streams,
431 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700432 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700433 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700434 return true;
435 }
436
Noah Richards2e7a0982015-05-18 14:02:54 -0700437 const bool include_rtx_streams =
438 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440
brandtr03d5fb12016-11-22 03:37:59 -0800441 const bool include_flexfec_stream =
442 ContainsFlexfecCodec(content_description->codecs());
443
zhihuang1c378ed2017-08-17 14:10:50 -0700444 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 // groupid is empty for StreamParams generated using
446 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700447 StreamParams* param =
448 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000449 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700450 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200451 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700452 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700454 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000455 // Add the generated ssrc.
456 for (size_t i = 0; i < ssrcs.size(); ++i) {
457 stream_param.ssrcs.push_back(ssrcs[i]);
458 }
zhihuang1c378ed2017-08-17 14:10:50 -0700459 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000460 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
461 stream_param.ssrc_groups.push_back(group);
462 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700463 // Generate extra ssrcs for include_rtx_streams case.
464 if (include_rtx_streams) {
465 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200466 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700467 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
468 &rtx_ssrcs);
469 for (size_t i = 0; i < ssrcs.size(); ++i) {
470 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
471 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 content_description->set_multistream(true);
473 }
brandtr03d5fb12016-11-22 03:37:59 -0800474 // Generate extra ssrc for include_flexfec_stream case.
475 if (include_flexfec_stream) {
476 // TODO(brandtr): Update when we support multistream protection.
477 if (ssrcs.size() == 1) {
478 std::vector<uint32_t> flexfec_ssrcs;
479 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
480 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
481 content_description->set_multistream(true);
482 } else if (!ssrcs.empty()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100483 RTC_LOG(LS_WARNING)
brandtr03d5fb12016-11-22 03:37:59 -0800484 << "Our FlexFEC implementation only supports protecting "
485 << "a single media streams. This session has multiple "
486 << "media streams however, so no FlexFEC SSRC will be generated.";
487 }
488 }
zhihuang1c378ed2017-08-17 14:10:50 -0700489 stream_param.cname = rtcp_cname;
Steve Anton8ffb9c32017-08-31 15:45:38 -0700490 // TODO(steveanton): Support any number of stream ids.
491 RTC_CHECK(sender.stream_ids.size() == 1U);
492 stream_param.sync_label = sender.stream_ids[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 content_description->AddStream(stream_param);
494
495 // Store the new StreamParams in current_streams.
496 // This is necessary so that we can use the CNAME for other media types.
497 current_streams->push_back(stream_param);
498 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700499 // Use existing generated SSRCs/groups, but update the sync_label if
500 // necessary. This may be needed if a MediaStreamTrack was moved from one
501 // MediaStream to another.
Steve Anton8ffb9c32017-08-31 15:45:38 -0700502 // TODO(steveanton): Support any number of stream ids.
503 RTC_CHECK(sender.stream_ids.size() == 1U);
504 param->sync_label = sender.stream_ids[0];
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000505 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 }
507 }
508 return true;
509}
510
511// Updates the transport infos of the |sdesc| according to the given
512// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800513// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
514// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
516 SessionDescription* sdesc) {
517 // The bundle should not be empty.
518 if (!sdesc || !bundle_group.FirstContentName()) {
519 return false;
520 }
521
522 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700523 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524 const TransportInfo* selected_transport_info =
525 sdesc->GetTransportInfoByName(selected_content_name);
526 if (!selected_transport_info) {
527 return false;
528 }
529
530 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700531 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700533 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800535 ConnectionRole selected_connection_role =
536 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 for (TransportInfos::iterator it =
538 sdesc->transport_infos().begin();
539 it != sdesc->transport_infos().end(); ++it) {
540 if (bundle_group.HasContentName(it->content_name) &&
541 it->content_name != selected_content_name) {
542 it->description.ice_ufrag = selected_ufrag;
543 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800544 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 }
546 }
547 return true;
548}
549
550// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
551// sets it to |cryptos|.
552static bool GetCryptosByName(const SessionDescription* sdesc,
553 const std::string& content_name,
554 CryptoParamsVec* cryptos) {
555 if (!sdesc || !cryptos) {
556 return false;
557 }
558
559 const ContentInfo* content = sdesc->GetContentByName(content_name);
560 if (!IsMediaContent(content) || !content->description) {
561 return false;
562 }
563
564 const MediaContentDescription* media_desc =
565 static_cast<const MediaContentDescription*>(content->description);
566 *cryptos = media_desc->cryptos();
567 return true;
568}
569
570// Predicate function used by the remove_if.
571// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
572static bool CryptoNotFound(const CryptoParams crypto,
573 const CryptoParamsVec* filter) {
574 if (filter == NULL) {
575 return true;
576 }
577 for (CryptoParamsVec::const_iterator it = filter->begin();
578 it != filter->end(); ++it) {
579 if (it->cipher_suite == crypto.cipher_suite) {
580 return false;
581 }
582 }
583 return true;
584}
585
586// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
587// which are not available in |filter|.
588static void PruneCryptos(const CryptoParamsVec& filter,
589 CryptoParamsVec* target_cryptos) {
590 if (!target_cryptos) {
591 return;
592 }
593 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
594 target_cryptos->end(),
595 bind2nd(ptr_fun(CryptoNotFound),
596 &filter)),
597 target_cryptos->end());
598}
599
deadbeefb5cb19b2015-11-23 16:39:12 -0800600static bool IsRtpProtocol(const std::string& protocol) {
601 return protocol.empty() ||
602 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
603}
604
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605static bool IsRtpContent(SessionDescription* sdesc,
606 const std::string& content_name) {
607 bool is_rtp = false;
608 ContentInfo* content = sdesc->GetContentByName(content_name);
609 if (IsMediaContent(content)) {
610 MediaContentDescription* media_desc =
611 static_cast<MediaContentDescription*>(content->description);
612 if (!media_desc) {
613 return false;
614 }
deadbeefb5cb19b2015-11-23 16:39:12 -0800615 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 }
617 return is_rtp;
618}
619
620// Updates the crypto parameters of the |sdesc| according to the given
621// |bundle_group|. The crypto parameters of all the contents within the
622// |bundle_group| should be updated to use the common subset of the
623// available cryptos.
624static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
625 SessionDescription* sdesc) {
626 // The bundle should not be empty.
627 if (!sdesc || !bundle_group.FirstContentName()) {
628 return false;
629 }
630
wu@webrtc.org78187522013-10-07 23:32:02 +0000631 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 // Get the common cryptos.
633 const ContentNames& content_names = bundle_group.content_names();
634 CryptoParamsVec common_cryptos;
635 for (ContentNames::const_iterator it = content_names.begin();
636 it != content_names.end(); ++it) {
637 if (!IsRtpContent(sdesc, *it)) {
638 continue;
639 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000640 // The common cryptos are needed if any of the content does not have DTLS
641 // enabled.
642 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
643 common_cryptos_needed = true;
644 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 if (it == content_names.begin()) {
646 // Initial the common_cryptos with the first content in the bundle group.
647 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
648 return false;
649 }
650 if (common_cryptos.empty()) {
651 // If there's no crypto params, we should just return.
652 return true;
653 }
654 } else {
655 CryptoParamsVec cryptos;
656 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
657 return false;
658 }
659 PruneCryptos(cryptos, &common_cryptos);
660 }
661 }
662
wu@webrtc.org78187522013-10-07 23:32:02 +0000663 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 return false;
665 }
666
667 // Update to use the common cryptos.
668 for (ContentNames::const_iterator it = content_names.begin();
669 it != content_names.end(); ++it) {
670 if (!IsRtpContent(sdesc, *it)) {
671 continue;
672 }
673 ContentInfo* content = sdesc->GetContentByName(*it);
674 if (IsMediaContent(content)) {
675 MediaContentDescription* media_desc =
676 static_cast<MediaContentDescription*>(content->description);
677 if (!media_desc) {
678 return false;
679 }
680 media_desc->set_cryptos(common_cryptos);
681 }
682 }
683 return true;
684}
685
686template <class C>
687static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800688 for (const auto& codec : codecs) {
689 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 return true;
691 }
692 }
693 return false;
694}
695
696template <class C>
697static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800698 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699}
700
brandtr03d5fb12016-11-22 03:37:59 -0800701template <class C>
702static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
703 for (const auto& codec : codecs) {
704 if (IsFlexfecCodec(codec)) {
705 return true;
706 }
707 }
708 return false;
709}
710
711template <class C>
712static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800713 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800714}
715
zhihuang1c378ed2017-08-17 14:10:50 -0700716// Create a media content to be offered for the given |sender_options|,
717// according to the given options.rtcp_mux, session_options.is_muc, codecs,
718// secure_transport, crypto, and current_streams. If we don't currently have
719// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
720// created (according to crypto_suites). The created content is added to the
721// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722template <class C>
723static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700724 const std::vector<SenderOptions>& sender_options,
725 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000727 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 const CryptoParamsVec* current_cryptos,
729 const std::vector<std::string>& crypto_suites,
730 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 StreamParamsVec* current_streams,
732 MediaContentDescriptionImpl<C>* offer) {
733 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734
zhihuang1c378ed2017-08-17 14:10:50 -0700735 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700736 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
737 offer->set_rtcp_reduced_size(true);
738 }
zhihuang1c378ed2017-08-17 14:10:50 -0700739 offer->set_multistream(session_options.is_muc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 offer->set_rtp_header_extensions(rtp_extensions);
741
zhihuang1c378ed2017-08-17 14:10:50 -0700742 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
743 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 return false;
745 }
746
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 if (secure_policy != SEC_DISABLED) {
748 if (current_cryptos) {
749 AddMediaCryptos(*current_cryptos, offer);
750 }
751 if (offer->cryptos().empty()) {
752 if (!CreateMediaCryptos(crypto_suites, offer)) {
753 return false;
754 }
755 }
756 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757
deadbeef7af91dd2016-12-13 11:29:11 -0800758 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 return false;
760 }
761 return true;
762}
763
764template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000765static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800766 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000767 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800768 const int codec2_id) {
769 const C* codec1 = FindCodecById(codecs1, codec1_id);
770 const C* codec2 = FindCodecById(codecs2, codec2_id);
771 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000772}
773
774template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775static void NegotiateCodecs(const std::vector<C>& local_codecs,
776 const std::vector<C>& offered_codecs,
777 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800778 for (const C& ours : local_codecs) {
779 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700780 // Note that we intentionally only find one matching codec for each of our
781 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800782 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
783 C negotiated = ours;
784 negotiated.IntersectFeedbackParams(theirs);
785 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800786 const auto apt_it =
787 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800788 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800789 RTC_DCHECK(apt_it != theirs.params.end());
790 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 }
magjedf823ede2016-11-12 09:53:04 -0800792 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
793 webrtc::H264::GenerateProfileLevelIdForAnswer(
794 ours.params, theirs.params, &negotiated.params);
795 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800796 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700797 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800798 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 }
800 }
deadbeef67cf2c12016-04-13 10:07:16 -0700801 // RFC3264: Although the answerer MAY list the formats in their desired
802 // order of preference, it is RECOMMENDED that unless there is a
803 // specific reason, the answerer list formats in the same relative order
804 // they were present in the offer.
805 std::unordered_map<int, int> payload_type_preferences;
806 int preference = static_cast<int>(offered_codecs.size() + 1);
807 for (const C& codec : offered_codecs) {
808 payload_type_preferences[codec.id] = preference--;
809 }
810 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
811 [&payload_type_preferences](const C& a, const C& b) {
812 return payload_type_preferences[a.id] >
813 payload_type_preferences[b.id];
814 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815}
816
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800817// Finds a codec in |codecs2| that matches |codec_to_match|, which is
818// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
819// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800821static bool FindMatchingCodec(const std::vector<C>& codecs1,
822 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 const C& codec_to_match,
824 C* found_codec) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -0700825 // |codec_to_match| should be a member of |codecs1|, in order to look up RTX
826 // codecs' associated codecs correctly. If not, that's a programming error.
827 RTC_DCHECK(std::find_if(codecs1.begin(), codecs1.end(),
828 [&codec_to_match](const C& codec) {
829 return &codec == &codec_to_match;
830 }) != codecs1.end());
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800831 for (const C& potential_match : codecs2) {
832 if (potential_match.Matches(codec_to_match)) {
833 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800834 int apt_value_1 = 0;
835 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800836 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
837 &apt_value_1) ||
838 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
839 &apt_value_2)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100840 RTC_LOG(LS_WARNING) << "RTX missing associated payload type.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800841 continue;
842 }
843 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
844 apt_value_2)) {
845 continue;
846 }
847 }
848 if (found_codec) {
849 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 }
851 return true;
852 }
853 }
854 return false;
855}
856
zhihuang1c378ed2017-08-17 14:10:50 -0700857// Find the codec in |codec_list| that |rtx_codec| is associated with.
858template <class C>
859static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
860 const C& rtx_codec) {
861 std::string associated_pt_str;
862 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
863 &associated_pt_str)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100864 RTC_LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
865 << " is missing an associated payload type.";
zhihuang1c378ed2017-08-17 14:10:50 -0700866 return nullptr;
867 }
868
869 int associated_pt;
870 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100871 RTC_LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
872 << " of RTX codec " << rtx_codec.name
873 << " to an integer.";
zhihuang1c378ed2017-08-17 14:10:50 -0700874 return nullptr;
875 }
876
877 // Find the associated reference codec for the reference RTX codec.
878 const C* associated_codec = FindCodecById(codec_list, associated_pt);
879 if (!associated_codec) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100880 RTC_LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
881 << associated_pt << " for RTX codec " << rtx_codec.name
882 << ".";
zhihuang1c378ed2017-08-17 14:10:50 -0700883 }
884 return associated_codec;
885}
886
887// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888// already exist in |offered_codecs| and ensure the payload types don't
889// collide.
890template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700891static void MergeCodecs(const std::vector<C>& reference_codecs,
892 std::vector<C>* offered_codecs,
893 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800895 for (const C& reference_codec : reference_codecs) {
896 if (!IsRtxCodec(reference_codec) &&
897 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
898 reference_codec, nullptr)) {
899 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 used_pltypes->FindAndSetIdUsed(&codec);
901 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 }
903 }
904
905 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800906 for (const C& reference_codec : reference_codecs) {
907 if (IsRtxCodec(reference_codec) &&
908 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
909 reference_codec, nullptr)) {
910 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700911 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700912 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700913 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700914 continue;
915 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800916 // Find a codec in the offered list that matches the reference codec.
917 // Its payload type may be different than the reference codec.
918 C matching_codec;
919 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800920 *associated_codec, &matching_codec)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100921 RTC_LOG(LS_WARNING)
922 << "Couldn't find matching " << associated_codec->name << " codec.";
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800923 continue;
924 }
925
926 rtx_codec.params[kCodecParamAssociatedPayloadType] =
927 rtc::ToString(matching_codec.id);
928 used_pltypes->FindAndSetIdUsed(&rtx_codec);
929 offered_codecs->push_back(rtx_codec);
930 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 }
932}
933
zhihuang1c378ed2017-08-17 14:10:50 -0700934static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
935 const webrtc::RtpExtension& ext_to_match,
936 webrtc::RtpExtension* found_extension) {
937 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
938 it != extensions.end(); ++it) {
939 // We assume that all URIs are given in a canonical format.
940 if (it->uri == ext_to_match.uri && it->encrypt == ext_to_match.encrypt) {
941 if (found_extension) {
942 *found_extension = *it;
943 }
944 return true;
945 }
946 }
947 return false;
948}
949
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000950static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700951 const webrtc::RtpExtension& ext_to_match,
952 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700953 // We assume that all URIs are given in a canonical format.
954 const webrtc::RtpExtension* found =
955 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
956 ext_to_match.uri);
957 if (!found) {
958 return false;
959 }
960 if (found_extension) {
961 *found_extension = *found;
962 }
963 return true;
964}
965
966static bool FindByUriWithEncryptionPreference(
967 const RtpHeaderExtensions& extensions,
968 const webrtc::RtpExtension& ext_to_match, bool encryption_preference,
969 webrtc::RtpExtension* found_extension) {
970 const webrtc::RtpExtension* unencrypted_extension = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
972 it != extensions.end(); ++it) {
973 // We assume that all URIs are given in a canonical format.
974 if (it->uri == ext_to_match.uri) {
jbauch5869f502017-06-29 12:31:36 -0700975 if (!encryption_preference || it->encrypt) {
976 if (found_extension) {
977 *found_extension = *it;
978 }
979 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 }
jbauch5869f502017-06-29 12:31:36 -0700981 unencrypted_extension = &(*it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982 }
983 }
jbauch5869f502017-06-29 12:31:36 -0700984 if (unencrypted_extension) {
985 if (found_extension) {
986 *found_extension = *unencrypted_extension;
987 }
988 return true;
989 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 return false;
991}
992
zhihuang1c378ed2017-08-17 14:10:50 -0700993// Adds all extensions from |reference_extensions| to |offered_extensions| that
994// don't already exist in |offered_extensions| and ensure the IDs don't
995// collide. If an extension is added, it's also added to |regular_extensions| or
996// |encrypted_extensions|, and if the extension is in |regular_extensions| or
997// |encrypted_extensions|, its ID is marked as used in |used_ids|.
998// |offered_extensions| is for either audio or video while |regular_extensions|
999// and |encrypted_extensions| are used for both audio and video. There could be
1000// overlap between audio extensions and video extensions.
1001static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1002 RtpHeaderExtensions* offered_extensions,
1003 RtpHeaderExtensions* regular_extensions,
1004 RtpHeaderExtensions* encrypted_extensions,
1005 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001006 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001007 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1008 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001009 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001010 if (reference_extension.encrypt) {
1011 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1012 &existing)) {
1013 offered_extensions->push_back(existing);
1014 } else {
1015 used_ids->FindAndSetIdUsed(&reference_extension);
1016 encrypted_extensions->push_back(reference_extension);
1017 offered_extensions->push_back(reference_extension);
1018 }
olka3c747662017-08-17 06:50:32 -07001019 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001020 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1021 &existing)) {
1022 offered_extensions->push_back(existing);
1023 } else {
1024 used_ids->FindAndSetIdUsed(&reference_extension);
1025 regular_extensions->push_back(reference_extension);
1026 offered_extensions->push_back(reference_extension);
1027 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001028 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 }
1030 }
1031}
1032
jbauch5869f502017-06-29 12:31:36 -07001033static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1034 RtpHeaderExtensions* all_extensions,
1035 UsedRtpHeaderExtensionIds* used_ids) {
1036 RtpHeaderExtensions encrypted_extensions;
1037 for (const webrtc::RtpExtension& extension : *extensions) {
1038 webrtc::RtpExtension existing;
1039 // Don't add encrypted extensions again that were already included in a
1040 // previous offer or regular extensions that are also included as encrypted
1041 // extensions.
1042 if (extension.encrypt ||
1043 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1044 (FindByUriWithEncryptionPreference(*extensions, extension, true,
1045 &existing) && existing.encrypt)) {
1046 continue;
1047 }
1048
1049 if (FindByUri(*all_extensions, extension, &existing)) {
1050 encrypted_extensions.push_back(existing);
1051 } else {
1052 webrtc::RtpExtension encrypted(extension);
1053 encrypted.encrypt = true;
1054 used_ids->FindAndSetIdUsed(&encrypted);
1055 all_extensions->push_back(encrypted);
1056 encrypted_extensions.push_back(encrypted);
1057 }
1058 }
1059 extensions->insert(extensions->end(), encrypted_extensions.begin(),
1060 encrypted_extensions.end());
1061}
1062
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063static void NegotiateRtpHeaderExtensions(
1064 const RtpHeaderExtensions& local_extensions,
1065 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001066 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067 RtpHeaderExtensions* negotiated_extenstions) {
1068 RtpHeaderExtensions::const_iterator ours;
1069 for (ours = local_extensions.begin();
1070 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 11:24:55 -07001071 webrtc::RtpExtension theirs;
jbauch5869f502017-06-29 12:31:36 -07001072 if (FindByUriWithEncryptionPreference(offered_extensions, *ours,
1073 enable_encrypted_rtp_header_extensions, &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 // We respond with their RTP header extension id.
1075 negotiated_extenstions->push_back(theirs);
1076 }
1077 }
1078}
1079
1080static void StripCNCodecs(AudioCodecs* audio_codecs) {
1081 AudioCodecs::iterator iter = audio_codecs->begin();
1082 while (iter != audio_codecs->end()) {
nisse21e4e0b2017-02-20 05:01:01 -08001083 if (STR_CASE_CMP(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084 iter = audio_codecs->erase(iter);
1085 } else {
1086 ++iter;
1087 }
1088 }
1089}
1090
zhihuang1c378ed2017-08-17 14:10:50 -07001091// Create a media content to be answered for the given |sender_options|
1092// according to the given session_options.rtcp_mux, session_options.streams,
1093// codecs, crypto, and current_streams. If we don't currently have crypto (in
1094// current_cryptos) and it is enabled (in secure_policy), crypto is created
1095// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1096// negotiated with the offer. If the negotiation fails, this method returns
1097// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098template <class C>
1099static bool CreateMediaContentAnswer(
1100 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001101 const MediaDescriptionOptions& media_description_options,
1102 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001104 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105 const CryptoParamsVec* current_cryptos,
1106 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001107 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109 bool bundle_enabled,
1110 MediaContentDescriptionImpl<C>* answer) {
1111 std::vector<C> negotiated_codecs;
1112 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1113 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114 answer->set_protocol(offer->protocol());
1115 RtpHeaderExtensions negotiated_rtp_extensions;
1116 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1117 offer->rtp_header_extensions(),
jbauch5869f502017-06-29 12:31:36 -07001118 enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001119 &negotiated_rtp_extensions);
1120 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1121
zhihuang1c378ed2017-08-17 14:10:50 -07001122 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001123 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1124 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1125 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126
1127 if (sdes_policy != SEC_DISABLED) {
1128 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001129 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1130 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 if (current_cryptos) {
1132 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1133 }
1134 answer->AddCrypto(crypto);
1135 }
1136 }
1137
deadbeef7af91dd2016-12-13 11:29:11 -08001138 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139 return false;
1140 }
1141
zhihuang1c378ed2017-08-17 14:10:50 -07001142 if (!AddStreamParams(media_description_options.sender_options,
1143 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 return false; // Something went seriously wrong.
1145 }
1146
Steve Anton4e70a722017-11-28 14:57:10 -08001147 answer->set_direction(NegotiateRtpTransceiverDirection(
1148 offer->direction(), media_description_options.direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001149 return true;
1150}
1151
1152static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001153 const std::string& protocol,
1154 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001155 // Since not all applications serialize and deserialize the media protocol,
1156 // we will have to accept |protocol| to be empty.
1157 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 return true;
1159 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001160
zhihuangcf5b37c2016-05-05 11:44:35 -07001161 if (type == MEDIA_TYPE_DATA) {
1162 // Check for SCTP, but also for RTP for RTP-based data channels.
1163 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1164 if (secure_transport) {
1165 // Most likely scenarios first.
1166 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1167 IsPlainRtp(protocol);
1168 } else {
1169 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1170 }
1171 }
1172
1173 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1174 // JSEP specifies.
1175 if (secure_transport) {
1176 // Most likely scenarios first.
1177 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1178 } else {
1179 return IsPlainRtp(protocol);
1180 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181}
1182
1183static void SetMediaProtocol(bool secure_transport,
1184 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001185 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001187 else if (secure_transport)
1188 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 else
1190 desc->set_protocol(kMediaProtocolAvpf);
1191}
1192
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001193// Gets the TransportInfo of the given |content_name| from the
1194// |current_description|. If doesn't exist, returns a new one.
1195static const TransportDescription* GetTransportDescription(
1196 const std::string& content_name,
1197 const SessionDescription* current_description) {
1198 const TransportDescription* desc = NULL;
1199 if (current_description) {
1200 const TransportInfo* info =
1201 current_description->GetTransportInfoByName(content_name);
1202 if (info) {
1203 desc = &info->description;
1204 }
1205 }
1206 return desc;
1207}
1208
1209// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001210static bool IsDtlsActive(const ContentInfo* content,
1211 const SessionDescription* current_description) {
1212 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001213 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001214 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001215
zhihuang1c378ed2017-08-17 14:10:50 -07001216 size_t msection_index = content - &current_description->contents()[0];
1217
1218 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001219 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001220 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001221
zhihuang1c378ed2017-08-17 14:10:50 -07001222 return current_description->transport_infos()[msection_index]
1223 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001224}
1225
Steve Anton8ffb9c32017-08-31 15:45:38 -07001226void MediaDescriptionOptions::AddAudioSender(
1227 const std::string& track_id,
1228 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001229 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001230 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001231}
1232
Steve Anton8ffb9c32017-08-31 15:45:38 -07001233void MediaDescriptionOptions::AddVideoSender(
1234 const std::string& track_id,
1235 const std::vector<std::string>& stream_ids,
1236 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001237 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001238 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001239}
1240
zhihuang1c378ed2017-08-17 14:10:50 -07001241void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1242 const std::string& stream_id) {
1243 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001244 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1245 // than one stream?
1246 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247}
1248
Steve Anton8ffb9c32017-08-31 15:45:38 -07001249void MediaDescriptionOptions::AddSenderInternal(
1250 const std::string& track_id,
1251 const std::vector<std::string>& stream_ids,
1252 int num_sim_layers) {
1253 // TODO(steveanton): Support any number of stream ids.
1254 RTC_CHECK(stream_ids.size() == 1U);
1255 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256}
1257
zhihuang1c378ed2017-08-17 14:10:50 -07001258bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1259 return std::find_if(media_description_options.begin(),
1260 media_description_options.end(),
1261 [type](const MediaDescriptionOptions& t) {
1262 return t.type == type;
1263 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001264}
1265
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1267 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001268 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269
1270MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1271 ChannelManager* channel_manager,
1272 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001273 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001274 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1275 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001277 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1279 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001280 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001281}
1282
ossudedfd282016-06-14 07:12:39 -07001283const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1284 const {
ossu075af922016-06-14 03:29:38 -07001285 return audio_sendrecv_codecs_;
1286}
1287
1288const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1289 return audio_send_codecs_;
1290}
1291
1292const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1293 return audio_recv_codecs_;
1294}
1295
1296void MediaSessionDescriptionFactory::set_audio_codecs(
1297 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1298 audio_send_codecs_ = send_codecs;
1299 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001300 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301}
1302
1303SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001304 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001306 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307
1308 StreamParamsVec current_streams;
1309 GetCurrentStreamParams(current_description, &current_streams);
1310
zhihuang1c378ed2017-08-17 14:10:50 -07001311 AudioCodecs offer_audio_codecs;
1312 VideoCodecs offer_video_codecs;
1313 DataCodecs offer_data_codecs;
1314 GetCodecsForOffer(current_description, &offer_audio_codecs,
1315 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001316
zhihuang1c378ed2017-08-17 14:10:50 -07001317 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001319 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 }
zhihuang1c378ed2017-08-17 14:10:50 -07001321 FilterDataCodecs(&offer_data_codecs,
1322 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323
1324 RtpHeaderExtensions audio_rtp_extensions;
1325 RtpHeaderExtensions video_rtp_extensions;
1326 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1327 &video_rtp_extensions);
1328
zhihuang1c378ed2017-08-17 14:10:50 -07001329 // Must have options for each existing section.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001330 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001331 RTC_DCHECK(current_description->contents().size() <=
1332 session_options.media_description_options.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001334
zhihuang1c378ed2017-08-17 14:10:50 -07001335 // Iterate through the media description options, matching with existing media
1336 // descriptions in |current_description|.
1337 int msection_index = 0;
1338 for (const MediaDescriptionOptions& media_description_options :
1339 session_options.media_description_options) {
1340 const ContentInfo* current_content = nullptr;
1341 if (current_description &&
1342 msection_index <
1343 static_cast<int>(current_description->contents().size())) {
1344 current_content = &current_description->contents()[msection_index];
1345 // Media type must match.
1346 RTC_DCHECK(IsMediaContentOfType(current_content,
1347 media_description_options.type));
1348 }
1349 switch (media_description_options.type) {
1350 case MEDIA_TYPE_AUDIO:
1351 if (!AddAudioContentForOffer(media_description_options, session_options,
1352 current_content, current_description,
1353 audio_rtp_extensions, offer_audio_codecs,
1354 &current_streams, offer.get())) {
1355 return nullptr;
1356 }
1357 break;
1358 case MEDIA_TYPE_VIDEO:
1359 if (!AddVideoContentForOffer(media_description_options, session_options,
1360 current_content, current_description,
1361 video_rtp_extensions, offer_video_codecs,
1362 &current_streams, offer.get())) {
1363 return nullptr;
1364 }
1365 break;
1366 case MEDIA_TYPE_DATA:
1367 if (!AddDataContentForOffer(media_description_options, session_options,
1368 current_content, current_description,
1369 offer_data_codecs, &current_streams,
1370 offer.get())) {
1371 return nullptr;
1372 }
1373 break;
1374 default:
1375 RTC_NOTREACHED();
1376 }
1377 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001378 }
1379
1380 // Bundle the contents together, if we've been asked to do so, and update any
1381 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001382 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001383 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001384 for (const ContentInfo& content : offer->contents()) {
1385 // TODO(deadbeef): There are conditions that make bundling two media
1386 // descriptions together illegal. For example, they use the same payload
1387 // type to represent different codecs, or same IDs for different header
1388 // extensions. We need to detect this and not try to bundle those media
1389 // descriptions together.
1390 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001391 }
1392 offer->AddGroup(offer_bundle);
1393 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001394 RTC_LOG(LS_ERROR)
1395 << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001396 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397 }
1398 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001399 RTC_LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001400 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001401 }
1402 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403 return offer.release();
1404}
1405
1406SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001407 const SessionDescription* offer,
1408 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001410 if (!offer) {
1411 return nullptr;
1412 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001413 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001414 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1415 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001416 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001417
1418 StreamParamsVec current_streams;
1419 GetCurrentStreamParams(current_description, &current_streams);
1420
deadbeefb7892532017-02-22 19:35:18 -08001421 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1422 // group in the answer with the appropriate content names.
1423 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1424 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1425 // Transport info shared by the bundle group.
1426 std::unique_ptr<TransportInfo> bundle_transport;
1427
zhihuang1c378ed2017-08-17 14:10:50 -07001428 // Get list of all possible codecs that respects existing payload type
1429 // mappings and uses a single payload type space.
1430 //
1431 // Note that these lists may be further filtered for each m= section; this
1432 // step is done just to establish the payload type mappings shared by all
1433 // sections.
1434 AudioCodecs answer_audio_codecs;
1435 VideoCodecs answer_video_codecs;
1436 DataCodecs answer_data_codecs;
1437 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
1438 &answer_video_codecs, &answer_data_codecs);
1439
1440 if (!session_options.vad_enabled) {
1441 // If application doesn't want CN codecs in answer.
1442 StripCNCodecs(&answer_audio_codecs);
1443 }
1444 FilterDataCodecs(&answer_data_codecs,
1445 session_options.data_channel_type == DCT_SCTP);
1446
1447 // Must have options for exactly as many sections as in the offer.
1448 RTC_DCHECK(offer->contents().size() ==
1449 session_options.media_description_options.size());
1450 // Iterate through the media description options, matching with existing
1451 // media descriptions in |current_description|.
1452 int msection_index = 0;
1453 for (const MediaDescriptionOptions& media_description_options :
1454 session_options.media_description_options) {
1455 const ContentInfo* offer_content = &offer->contents()[msection_index];
1456 // Media types and MIDs must match between the remote offer and the
1457 // MediaDescriptionOptions.
1458 RTC_DCHECK(
1459 IsMediaContentOfType(offer_content, media_description_options.type));
1460 RTC_DCHECK(media_description_options.mid == offer_content->name);
1461 const ContentInfo* current_content = nullptr;
1462 if (current_description &&
1463 msection_index <
1464 static_cast<int>(current_description->contents().size())) {
1465 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001466 }
zhihuang1c378ed2017-08-17 14:10:50 -07001467 switch (media_description_options.type) {
1468 case MEDIA_TYPE_AUDIO:
1469 if (!AddAudioContentForAnswer(
1470 media_description_options, session_options, offer_content,
1471 offer, current_content, current_description,
1472 bundle_transport.get(), answer_audio_codecs, &current_streams,
1473 answer.get())) {
1474 return nullptr;
1475 }
1476 break;
1477 case MEDIA_TYPE_VIDEO:
1478 if (!AddVideoContentForAnswer(
1479 media_description_options, session_options, offer_content,
1480 offer, current_content, current_description,
1481 bundle_transport.get(), answer_video_codecs, &current_streams,
1482 answer.get())) {
1483 return nullptr;
1484 }
1485 break;
1486 case MEDIA_TYPE_DATA:
1487 if (!AddDataContentForAnswer(media_description_options, session_options,
1488 offer_content, offer, current_content,
1489 current_description,
1490 bundle_transport.get(), answer_data_codecs,
1491 &current_streams, answer.get())) {
1492 return nullptr;
1493 }
1494 break;
1495 default:
1496 RTC_NOTREACHED();
1497 }
1498 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001499 // See if we can add the newly generated m= section to the BUNDLE group in
1500 // the answer.
1501 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001502 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001503 offer_bundle->HasContentName(added.name)) {
1504 answer_bundle.AddContentName(added.name);
1505 bundle_transport.reset(
1506 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508 }
1509
deadbeefb7892532017-02-22 19:35:18 -08001510 // Only put BUNDLE group in answer if nonempty.
1511 if (answer_bundle.FirstContentName()) {
1512 answer->AddGroup(answer_bundle);
1513
1514 // Share the same ICE credentials and crypto params across all contents,
1515 // as BUNDLE requires.
1516 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001517 RTC_LOG(LS_ERROR)
1518 << "CreateAnswer failed to UpdateTransportInfoForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001519 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001520 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521
deadbeefb7892532017-02-22 19:35:18 -08001522 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001523 RTC_LOG(LS_ERROR)
1524 << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
deadbeefb7892532017-02-22 19:35:18 -08001525 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 }
1527 }
1528
1529 return answer.release();
1530}
1531
ossu075af922016-06-14 03:29:38 -07001532const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1533 const RtpTransceiverDirection& direction) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001534 switch (direction) {
1535 // If stream is inactive - generate list as if sendrecv.
1536 case RtpTransceiverDirection::kSendRecv:
1537 case RtpTransceiverDirection::kInactive:
1538 return audio_sendrecv_codecs_;
1539 case RtpTransceiverDirection::kSendOnly:
1540 return audio_send_codecs_;
1541 case RtpTransceiverDirection::kRecvOnly:
1542 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001543 }
Steve Anton1d03a752017-11-27 14:30:09 -08001544 RTC_NOTREACHED();
1545 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001546}
1547
1548const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1549 const RtpTransceiverDirection& offer,
1550 const RtpTransceiverDirection& answer) const {
Steve Anton1d03a752017-11-27 14:30:09 -08001551 switch (answer) {
1552 // For inactive and sendrecv answers, generate lists as if we were to accept
1553 // the offer's direction. See RFC 3264 Section 6.1.
1554 case RtpTransceiverDirection::kSendRecv:
1555 case RtpTransceiverDirection::kInactive:
1556 return GetAudioCodecsForOffer(
1557 webrtc::RtpTransceiverDirectionReversed(offer));
1558 case RtpTransceiverDirection::kSendOnly:
ossu075af922016-06-14 03:29:38 -07001559 return audio_send_codecs_;
Steve Anton1d03a752017-11-27 14:30:09 -08001560 case RtpTransceiverDirection::kRecvOnly:
1561 return audio_recv_codecs_;
ossu075af922016-06-14 03:29:38 -07001562 }
Steve Anton1d03a752017-11-27 14:30:09 -08001563 RTC_NOTREACHED();
1564 return audio_sendrecv_codecs_;
ossu075af922016-06-14 03:29:38 -07001565}
1566
zhihuang1c378ed2017-08-17 14:10:50 -07001567void MergeCodecsFromDescription(const SessionDescription* description,
1568 AudioCodecs* audio_codecs,
1569 VideoCodecs* video_codecs,
1570 DataCodecs* data_codecs,
1571 UsedPayloadTypes* used_pltypes) {
1572 RTC_DCHECK(description);
1573 for (const ContentInfo& content : description->contents()) {
1574 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1575 const AudioContentDescription* audio =
1576 static_cast<AudioContentDescription*>(content.description);
1577 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1578 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1579 const VideoContentDescription* video =
1580 static_cast<VideoContentDescription*>(content.description);
1581 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1582 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1583 const DataContentDescription* data =
1584 static_cast<DataContentDescription*>(content.description);
1585 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1586 }
1587 }
1588}
1589
1590// Getting codecs for an offer involves these steps:
1591//
1592// 1. Construct payload type -> codec mappings for current description.
1593// 2. Add any reference codecs that weren't already present
1594// 3. For each individual media description (m= section), filter codecs based
1595// on the directional attribute (happens in another method).
1596void MediaSessionDescriptionFactory::GetCodecsForOffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597 const SessionDescription* current_description,
1598 AudioCodecs* audio_codecs,
1599 VideoCodecs* video_codecs,
1600 DataCodecs* data_codecs) const {
1601 UsedPayloadTypes used_pltypes;
1602 audio_codecs->clear();
1603 video_codecs->clear();
1604 data_codecs->clear();
1605
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001606 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001607 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1608 // new media type is added.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001610 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1611 data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612 }
1613
1614 // Add our codecs that are not in |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001615 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1616 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1617 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1618}
1619
1620// Getting codecs for an answer involves these steps:
1621//
1622// 1. Construct payload type -> codec mappings for current description.
1623// 2. Add any codecs from the offer that weren't already present.
1624// 3. Add any remaining codecs that weren't already present.
1625// 4. For each individual media description (m= section), filter codecs based
1626// on the directional attribute (happens in another method).
1627void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1628 const SessionDescription* current_description,
1629 const SessionDescription* remote_offer,
1630 AudioCodecs* audio_codecs,
1631 VideoCodecs* video_codecs,
1632 DataCodecs* data_codecs) const {
1633 UsedPayloadTypes used_pltypes;
1634 audio_codecs->clear();
1635 video_codecs->clear();
1636 data_codecs->clear();
1637
1638 // First - get all codecs from the current description if the media type
1639 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1640 // new media type is added.
1641 if (current_description) {
1642 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1643 data_codecs, &used_pltypes);
1644 }
1645
1646 // Second - filter out codecs that we don't support at all and should ignore.
1647 AudioCodecs filtered_offered_audio_codecs;
1648 VideoCodecs filtered_offered_video_codecs;
1649 DataCodecs filtered_offered_data_codecs;
1650 for (const ContentInfo& content : remote_offer->contents()) {
1651 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1652 const AudioContentDescription* audio =
1653 static_cast<AudioContentDescription*>(content.description);
1654 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1655 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1656 filtered_offered_audio_codecs,
1657 offered_audio_codec, nullptr) &&
1658 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1659 offered_audio_codec, nullptr)) {
1660 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1661 }
1662 }
1663 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1664 const VideoContentDescription* video =
1665 static_cast<VideoContentDescription*>(content.description);
1666 for (const VideoCodec& offered_video_codec : video->codecs()) {
1667 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1668 filtered_offered_video_codecs,
1669 offered_video_codec, nullptr) &&
1670 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1671 offered_video_codec, nullptr)) {
1672 filtered_offered_video_codecs.push_back(offered_video_codec);
1673 }
1674 }
1675 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1676 const DataContentDescription* data =
1677 static_cast<DataContentDescription*>(content.description);
1678 for (const DataCodec& offered_data_codec : data->codecs()) {
1679 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1680 filtered_offered_data_codecs,
1681 offered_data_codec, nullptr) &&
1682 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1683 offered_data_codec, nullptr)) {
1684 filtered_offered_data_codecs.push_back(offered_data_codec);
1685 }
1686 }
1687 }
1688 }
1689
1690 // Add codecs that are not in |current_description| but were in
1691 // |remote_offer|.
1692 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1693 &used_pltypes);
1694 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1695 &used_pltypes);
1696 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1697 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698}
1699
1700void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1701 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001702 RtpHeaderExtensions* offer_audio_extensions,
1703 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001704 // All header extensions allocated from the same range to avoid potential
1705 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001707 RtpHeaderExtensions all_regular_extensions;
1708 RtpHeaderExtensions all_encrypted_extensions;
zhihuang1c378ed2017-08-17 14:10:50 -07001709 offer_audio_extensions->clear();
1710 offer_video_extensions->clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001711
1712 // First - get all extensions from the current description if the media type
1713 // is used.
1714 // Add them to |used_ids| so the local ids are not reused if a new media
1715 // type is added.
1716 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001717 for (const ContentInfo& content : current_description->contents()) {
1718 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1719 const AudioContentDescription* audio =
1720 static_cast<const AudioContentDescription*>(content.description);
1721 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1722 &all_regular_extensions, &all_encrypted_extensions,
1723 &used_ids);
1724 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1725 const VideoContentDescription* video =
1726 static_cast<const VideoContentDescription*>(content.description);
1727 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1728 &all_regular_extensions, &all_encrypted_extensions,
1729 &used_ids);
1730 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 }
1732 }
1733
1734 // Add our default RTP header extensions that are not in
1735 // |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001736 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1737 &all_regular_extensions, &all_encrypted_extensions,
1738 &used_ids);
1739 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1740 &all_regular_extensions, &all_encrypted_extensions,
1741 &used_ids);
1742
jbauch5869f502017-06-29 12:31:36 -07001743 // TODO(jbauch): Support adding encrypted header extensions to existing
1744 // sessions.
1745 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001746 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1747 &all_encrypted_extensions, &used_ids);
1748 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1749 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001750 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751}
1752
1753bool MediaSessionDescriptionFactory::AddTransportOffer(
1754 const std::string& content_name,
1755 const TransportOptions& transport_options,
1756 const SessionDescription* current_desc,
1757 SessionDescription* offer_desc) const {
1758 if (!transport_desc_factory_)
1759 return false;
1760 const TransportDescription* current_tdesc =
1761 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001762 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1764 bool ret = (new_tdesc.get() != NULL &&
1765 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1766 if (!ret) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001767 RTC_LOG(LS_ERROR) << "Failed to AddTransportOffer, content name="
1768 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001769 }
1770 return ret;
1771}
1772
1773TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1774 const std::string& content_name,
1775 const SessionDescription* offer_desc,
1776 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001777 const SessionDescription* current_desc,
1778 bool require_transport_attributes) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779 if (!transport_desc_factory_)
1780 return NULL;
1781 const TransportDescription* offer_tdesc =
1782 GetTransportDescription(content_name, offer_desc);
1783 const TransportDescription* current_tdesc =
1784 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001785 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1786 require_transport_attributes,
1787 current_tdesc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788}
1789
1790bool MediaSessionDescriptionFactory::AddTransportAnswer(
1791 const std::string& content_name,
1792 const TransportDescription& transport_desc,
1793 SessionDescription* answer_desc) const {
1794 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1795 transport_desc))) {
Mirko Bonadei675513b2017-11-09 11:09:25 +01001796 RTC_LOG(LS_ERROR) << "Failed to AddTransportAnswer, content name="
1797 << content_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798 return false;
1799 }
1800 return true;
1801}
1802
zhihuang1c378ed2017-08-17 14:10:50 -07001803// |audio_codecs| = set of all possible codecs that can be used, with correct
1804// payload type mappings
1805//
1806// |supported_audio_codecs| = set of codecs that are supported for the direction
1807// of this m= section
1808//
1809// acd->codecs() = set of previously negotiated codecs for this m= section
1810//
1811// The payload types should come from audio_codecs, but the order should come
1812// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1813// change existing codec priority, and that new codecs are added with the right
1814// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001815bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001816 const MediaDescriptionOptions& media_description_options,
1817 const MediaSessionOptions& session_options,
1818 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001819 const SessionDescription* current_description,
1820 const RtpHeaderExtensions& audio_rtp_extensions,
1821 const AudioCodecs& audio_codecs,
1822 StreamParamsVec* current_streams,
1823 SessionDescription* desc) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001824 // Filter audio_codecs (which includes all codecs, with correctly remapped
1825 // payload types) based on transceiver direction.
1826 const AudioCodecs& supported_audio_codecs =
1827 GetAudioCodecsForOffer(media_description_options.direction);
1828
1829 AudioCodecs filtered_codecs;
1830 // Add the codecs from current content if exists.
1831 if (current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001832 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07001833 const AudioContentDescription* acd =
1834 static_cast<const AudioContentDescription*>(
1835 current_content->description);
1836 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001837 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
1838 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07001839 filtered_codecs.push_back(codec);
1840 }
1841 }
1842 }
1843 // Add other supported audio codecs.
1844 AudioCodec found_codec;
1845 for (const AudioCodec& codec : supported_audio_codecs) {
1846 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1847 codec, &found_codec) &&
1848 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1849 codec, nullptr)) {
1850 // Use the |found_codec| from |audio_codecs| because it has the correctly
1851 // mapped payload type.
1852 filtered_codecs.push_back(found_codec);
1853 }
1854 }
deadbeef44f08192015-12-15 16:20:09 -08001855
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001856 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001857 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1858 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001859
kwiberg31022942016-03-11 14:18:21 -08001860 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001861 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001862 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1863 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001864 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001865 media_description_options.sender_options, session_options,
1866 filtered_codecs, sdes_policy, GetCryptos(current_content),
1867 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001868 return false;
1869 }
1870 audio->set_lang(lang_);
1871
1872 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1873 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001874
Steve Anton4e70a722017-11-28 14:57:10 -08001875 audio->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001876
zhihuang1c378ed2017-08-17 14:10:50 -07001877 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1878 media_description_options.stopped, audio.release());
1879 if (!AddTransportOffer(media_description_options.mid,
1880 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001881 current_description, desc)) {
1882 return false;
1883 }
1884
1885 return true;
1886}
1887
1888bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001889 const MediaDescriptionOptions& media_description_options,
1890 const MediaSessionOptions& session_options,
1891 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001892 const SessionDescription* current_description,
1893 const RtpHeaderExtensions& video_rtp_extensions,
1894 const VideoCodecs& video_codecs,
1895 StreamParamsVec* current_streams,
1896 SessionDescription* desc) const {
1897 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001898 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1899 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001900
kwiberg31022942016-03-11 14:18:21 -08001901 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001902 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001903 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1904 &crypto_suites);
1905
1906 VideoCodecs filtered_codecs;
1907 // Add the codecs from current content if exists.
1908 if (current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001909 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07001910 const VideoContentDescription* vcd =
1911 static_cast<const VideoContentDescription*>(
1912 current_content->description);
1913 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07001914 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07001915 nullptr)) {
1916 filtered_codecs.push_back(codec);
1917 }
1918 }
1919 }
1920 // Add other supported video codecs.
1921 VideoCodec found_codec;
1922 for (const VideoCodec& codec : video_codecs_) {
1923 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1924 &found_codec) &&
1925 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1926 nullptr)) {
1927 // Use the |found_codec| from |video_codecs| because it has the correctly
1928 // mapped payload type.
1929 filtered_codecs.push_back(found_codec);
1930 }
1931 }
1932
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001933 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001934 media_description_options.sender_options, session_options,
1935 filtered_codecs, sdes_policy, GetCryptos(current_content),
1936 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001937 return false;
1938 }
1939
zhihuang1c378ed2017-08-17 14:10:50 -07001940 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001941
1942 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1943 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001944
Steve Anton4e70a722017-11-28 14:57:10 -08001945 video->set_direction(media_description_options.direction);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001946
zhihuang1c378ed2017-08-17 14:10:50 -07001947 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1948 media_description_options.stopped, video.release());
1949 if (!AddTransportOffer(media_description_options.mid,
1950 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001951 current_description, desc)) {
1952 return false;
1953 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001954 return true;
1955}
1956
1957bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001958 const MediaDescriptionOptions& media_description_options,
1959 const MediaSessionOptions& session_options,
1960 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001961 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001962 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001963 StreamParamsVec* current_streams,
1964 SessionDescription* desc) const {
1965 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1966
kwiberg31022942016-03-11 14:18:21 -08001967 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07001968 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
1969 // If the DataChannel type is not specified, use the DataChannel type in
1970 // the current description.
1971 if (session_options.data_channel_type == DCT_NONE && current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07001972 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
zhihuang1c378ed2017-08-17 14:10:50 -07001973 is_sctp = (static_cast<const DataContentDescription*>(
1974 current_content->description)
1975 ->protocol() == kMediaProtocolSctp);
1976 }
deadbeef44f08192015-12-15 16:20:09 -08001977
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001978 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001979 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1980 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001981 std::vector<std::string> crypto_suites;
1982 if (is_sctp) {
1983 // SDES doesn't make sense for SCTP, so we disable it, and we only
1984 // get SDES crypto suites for RTP-based data channels.
1985 sdes_policy = cricket::SEC_DISABLED;
1986 // Unlike SetMediaProtocol below, we need to set the protocol
1987 // before we call CreateMediaContentOffer. Otherwise,
1988 // CreateMediaContentOffer won't know this is SCTP and will
1989 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07001990 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
1991 // it's safe to do so. Older versions of webrtc would reject these
1992 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001993 data->set_protocol(
1994 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
1995 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001996 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07001997 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001998 }
1999
zhihuang1c378ed2017-08-17 14:10:50 -07002000 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002001 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002002 media_description_options.sender_options, session_options,
2003 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2004 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002005 return false;
2006 }
2007
2008 if (is_sctp) {
zhihuang1c378ed2017-08-17 14:10:50 -07002009 desc->AddContent(media_description_options.mid, NS_JINGLE_DRAFT_SCTP,
2010 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002011 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002012 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002013 SetMediaProtocol(secure_transport, data.get());
zhihuang1c378ed2017-08-17 14:10:50 -07002014 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
2015 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002016 }
zhihuang1c378ed2017-08-17 14:10:50 -07002017 if (!AddTransportOffer(media_description_options.mid,
2018 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002019 current_description, desc)) {
2020 return false;
2021 }
2022 return true;
2023}
2024
zhihuang1c378ed2017-08-17 14:10:50 -07002025// |audio_codecs| = set of all possible codecs that can be used, with correct
2026// payload type mappings
2027//
2028// |supported_audio_codecs| = set of codecs that are supported for the direction
2029// of this m= section
2030//
2031// acd->codecs() = set of previously negotiated codecs for this m= section
2032//
2033// The payload types should come from audio_codecs, but the order should come
2034// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2035// change existing codec priority, and that new codecs are added with the right
2036// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002037bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002038 const MediaDescriptionOptions& media_description_options,
2039 const MediaSessionOptions& session_options,
2040 const ContentInfo* offer_content,
2041 const SessionDescription* offer_description,
2042 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002043 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002044 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002045 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002046 StreamParamsVec* current_streams,
2047 SessionDescription* answer) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002048 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002049 const AudioContentDescription* offer_audio_description =
2050 static_cast<const AudioContentDescription*>(offer_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002051
deadbeefb7892532017-02-22 19:35:18 -08002052 std::unique_ptr<TransportDescription> audio_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002053 CreateTransportAnswer(media_description_options.mid, offer_description,
2054 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002055 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002056 if (!audio_transport) {
2057 return false;
2058 }
2059
zhihuang1c378ed2017-08-17 14:10:50 -07002060 // Pick codecs based on the requested communications direction in the offer
2061 // and the selected direction in the answer.
2062 // Note these will be filtered one final time in CreateMediaContentAnswer.
2063 auto wants_rtd = media_description_options.direction;
Steve Anton4e70a722017-11-28 14:57:10 -08002064 auto offer_rtd = offer_audio_description->direction();
ossu075af922016-06-14 03:29:38 -07002065 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002066 AudioCodecs supported_audio_codecs =
2067 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2068
2069 AudioCodecs filtered_codecs;
2070 // Add the codecs from current content if exists.
2071 if (current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002072 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
zhihuang1c378ed2017-08-17 14:10:50 -07002073 const AudioContentDescription* acd =
2074 static_cast<const AudioContentDescription*>(
2075 current_content->description);
2076 for (const AudioCodec& codec : acd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002077 if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
2078 nullptr)) {
zhihuang1c378ed2017-08-17 14:10:50 -07002079 filtered_codecs.push_back(codec);
2080 }
2081 }
2082 }
2083 // Add other supported audio codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002084 for (const AudioCodec& codec : supported_audio_codecs) {
2085 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
Zhi Huang6f367472017-11-22 13:20:02 -08002086 codec, nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002087 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2088 codec, nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002089 // We should use the local codec with local parameters and the codec id
2090 // would be correctly mapped in |NegotiateCodecs|.
2091 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002092 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002093 }
2094
zhihuang1c378ed2017-08-17 14:10:50 -07002095 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2096 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002097 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002098 new AudioContentDescription());
2099 // Do not require or create SDES cryptos if DTLS is used.
2100 cricket::SecurePolicy sdes_policy =
2101 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2102 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002103 offer_audio_description, media_description_options, session_options,
2104 filtered_codecs, sdes_policy, GetCryptos(current_content),
2105 audio_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2106 current_streams, bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002107 return false; // Fails the session setup.
2108 }
2109
deadbeefb7892532017-02-22 19:35:18 -08002110 bool secure = bundle_transport ? bundle_transport->description.secure()
2111 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002112 bool rejected = media_description_options.stopped ||
2113 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002114 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2115 audio_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002116 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002117 AddTransportAnswer(media_description_options.mid, *(audio_transport.get()),
2118 answer);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002119 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002120 RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2121 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002122 }
2123
zhihuang1c378ed2017-08-17 14:10:50 -07002124 answer->AddContent(media_description_options.mid, offer_content->type,
2125 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002126 return true;
2127}
2128
2129bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002130 const MediaDescriptionOptions& media_description_options,
2131 const MediaSessionOptions& session_options,
2132 const ContentInfo* offer_content,
2133 const SessionDescription* offer_description,
2134 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002135 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002136 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002137 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002138 StreamParamsVec* current_streams,
2139 SessionDescription* answer) const {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002140 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002141 const VideoContentDescription* offer_video_description =
2142 static_cast<const VideoContentDescription*>(offer_content->description);
2143
deadbeefb7892532017-02-22 19:35:18 -08002144 std::unique_ptr<TransportDescription> video_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002145 CreateTransportAnswer(media_description_options.mid, offer_description,
2146 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002147 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002148 if (!video_transport) {
2149 return false;
2150 }
2151
zhihuang1c378ed2017-08-17 14:10:50 -07002152 VideoCodecs filtered_codecs;
2153 // Add the codecs from current content if exists.
2154 if (current_content) {
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002155 RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
zhihuang1c378ed2017-08-17 14:10:50 -07002156 const VideoContentDescription* vcd =
2157 static_cast<const VideoContentDescription*>(
2158 current_content->description);
2159 for (const VideoCodec& codec : vcd->codecs()) {
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002160 if (FindMatchingCodec<VideoCodec>(vcd->codecs(), video_codecs, codec,
zhihuang1c378ed2017-08-17 14:10:50 -07002161 nullptr)) {
2162 filtered_codecs.push_back(codec);
2163 }
2164 }
2165 }
2166 // Add other supported video codecs.
zhihuang1c378ed2017-08-17 14:10:50 -07002167 for (const VideoCodec& codec : video_codecs_) {
2168 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
Zhi Huang6f367472017-11-22 13:20:02 -08002169 nullptr) &&
zhihuang1c378ed2017-08-17 14:10:50 -07002170 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2171 nullptr)) {
Zhi Huang6f367472017-11-22 13:20:02 -08002172 // We should use the local codec with local parameters and the codec id
2173 // would be correctly mapped in |NegotiateCodecs|.
2174 filtered_codecs.push_back(codec);
zhihuang1c378ed2017-08-17 14:10:50 -07002175 }
2176 }
2177
2178 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2179 session_options.bundle_enabled;
2180
kwiberg31022942016-03-11 14:18:21 -08002181 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002182 new VideoContentDescription());
2183 // Do not require or create SDES cryptos if DTLS is used.
2184 cricket::SecurePolicy sdes_policy =
2185 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002186 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002187 offer_video_description, media_description_options, session_options,
2188 filtered_codecs, sdes_policy, GetCryptos(current_content),
2189 video_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2190 current_streams, bundle_enabled, video_answer.get())) {
2191 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002192 }
deadbeefb7892532017-02-22 19:35:18 -08002193 bool secure = bundle_transport ? bundle_transport->description.secure()
2194 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002195 bool rejected = media_description_options.stopped ||
2196 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002197 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2198 video_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002199 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002200 if (!AddTransportAnswer(media_description_options.mid,
2201 *(video_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002202 return false;
2203 }
zhihuang1c378ed2017-08-17 14:10:50 -07002204 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002205 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +01002206 RTC_LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2207 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002208 }
zhihuang1c378ed2017-08-17 14:10:50 -07002209 answer->AddContent(media_description_options.mid, offer_content->type,
2210 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002211 return true;
2212}
2213
2214bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002215 const MediaDescriptionOptions& media_description_options,
2216 const MediaSessionOptions& session_options,
2217 const ContentInfo* offer_content,
2218 const SessionDescription* offer_description,
2219 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002220 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002221 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002222 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002223 StreamParamsVec* current_streams,
2224 SessionDescription* answer) const {
deadbeefb7892532017-02-22 19:35:18 -08002225 std::unique_ptr<TransportDescription> data_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002226 CreateTransportAnswer(media_description_options.mid, offer_description,
2227 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002228 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002229 if (!data_transport) {
2230 return false;
2231 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002232
kwiberg31022942016-03-11 14:18:21 -08002233 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002234 new DataContentDescription());
2235 // Do not require or create SDES cryptos if DTLS is used.
2236 cricket::SecurePolicy sdes_policy =
2237 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002238 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2239 session_options.bundle_enabled;
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002240 RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
2241 const DataContentDescription* offer_data_description =
2242 static_cast<const DataContentDescription*>(offer_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002243 if (!CreateMediaContentAnswer(
Taylor Brandstetter80cfb522017-10-12 20:37:38 -07002244 offer_data_description, media_description_options, session_options,
2245 data_codecs, sdes_policy, GetCryptos(current_content),
2246 RtpHeaderExtensions(), enable_encrypted_rtp_header_extensions_,
2247 current_streams, bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002248 return false; // Fails the session setup.
2249 }
2250
zstein4b2e0822017-02-17 19:48:38 -08002251 // Respond with sctpmap if the offer uses sctpmap.
zstein4b2e0822017-02-17 19:48:38 -08002252 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2253 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2254
deadbeefb7892532017-02-22 19:35:18 -08002255 bool secure = bundle_transport ? bundle_transport->description.secure()
2256 : data_transport->secure();
2257
zhihuang1c378ed2017-08-17 14:10:50 -07002258 bool rejected = session_options.data_channel_type == DCT_NONE ||
2259 media_description_options.stopped ||
2260 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002261 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2262 data_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002263 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002264 data_answer->set_bandwidth(kDataMaxBandwidth);
2265 if (!AddTransportAnswer(media_description_options.mid,
2266 *(data_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002267 return false;
2268 }
2269 } else {
2270 // RFC 3264
2271 // The answer MUST contain the same number of m-lines as the offer.
Mirko Bonadei675513b2017-11-09 11:09:25 +01002272 RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002273 }
zhihuang1c378ed2017-08-17 14:10:50 -07002274 answer->AddContent(media_description_options.mid, offer_content->type,
2275 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002276 return true;
2277}
2278
zhihuang1c378ed2017-08-17 14:10:50 -07002279void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2280 audio_sendrecv_codecs_.clear();
2281 all_audio_codecs_.clear();
2282 // Compute the audio codecs union.
2283 for (const AudioCodec& send : audio_send_codecs_) {
2284 all_audio_codecs_.push_back(send);
2285 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2286 send, nullptr)) {
2287 // It doesn't make sense to have an RTX codec we support sending but not
2288 // receiving.
2289 RTC_DCHECK(!IsRtxCodec(send));
2290 }
2291 }
2292 for (const AudioCodec& recv : audio_recv_codecs_) {
2293 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2294 recv, nullptr)) {
2295 all_audio_codecs_.push_back(recv);
2296 }
2297 }
2298 // Use NegotiateCodecs to merge our codec lists, since the operation is
2299 // essentially the same. Put send_codecs as the offered_codecs, which is the
2300 // order we'd like to follow. The reasoning is that encoding is usually more
2301 // expensive than decoding, and prioritizing a codec in the send list probably
2302 // means it's a codec we can handle efficiently.
2303 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2304 &audio_sendrecv_codecs_);
2305}
2306
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002307bool IsMediaContent(const ContentInfo* content) {
2308 return (content &&
2309 (content->type == NS_JINGLE_RTP ||
2310 content->type == NS_JINGLE_DRAFT_SCTP));
2311}
2312
2313bool IsAudioContent(const ContentInfo* content) {
2314 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2315}
2316
2317bool IsVideoContent(const ContentInfo* content) {
2318 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2319}
2320
2321bool IsDataContent(const ContentInfo* content) {
2322 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2323}
2324
deadbeef0ed85b22016-02-23 17:24:52 -08002325const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2326 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002327 for (const ContentInfo& content : contents) {
2328 if (IsMediaContentOfType(&content, media_type)) {
2329 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002330 }
2331 }
deadbeef0ed85b22016-02-23 17:24:52 -08002332 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333}
2334
2335const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2336 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2337}
2338
2339const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2340 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2341}
2342
2343const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2344 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2345}
2346
2347static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2348 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002349 if (sdesc == nullptr) {
2350 return nullptr;
2351 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002352
2353 return GetFirstMediaContent(sdesc->contents(), media_type);
2354}
2355
2356const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2357 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2358}
2359
2360const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2361 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2362}
2363
2364const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2365 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2366}
2367
2368const MediaContentDescription* GetFirstMediaContentDescription(
2369 const SessionDescription* sdesc, MediaType media_type) {
2370 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2371 const ContentDescription* description = content ? content->description : NULL;
2372 return static_cast<const MediaContentDescription*>(description);
2373}
2374
2375const AudioContentDescription* GetFirstAudioContentDescription(
2376 const SessionDescription* sdesc) {
2377 return static_cast<const AudioContentDescription*>(
2378 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2379}
2380
2381const VideoContentDescription* GetFirstVideoContentDescription(
2382 const SessionDescription* sdesc) {
2383 return static_cast<const VideoContentDescription*>(
2384 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2385}
2386
2387const DataContentDescription* GetFirstDataContentDescription(
2388 const SessionDescription* sdesc) {
2389 return static_cast<const DataContentDescription*>(
2390 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2391}
2392
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002393//
2394// Non-const versions of the above functions.
2395//
2396
Steve Anton36b29d12017-10-30 09:57:42 -07002397ContentInfo* GetFirstMediaContent(ContentInfos* contents,
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002398 MediaType media_type) {
Steve Anton36b29d12017-10-30 09:57:42 -07002399 for (ContentInfo& content : *contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002400 if (IsMediaContentOfType(&content, media_type)) {
2401 return &content;
2402 }
2403 }
2404 return nullptr;
2405}
2406
Steve Anton36b29d12017-10-30 09:57:42 -07002407ContentInfo* GetFirstAudioContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002408 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2409}
2410
Steve Anton36b29d12017-10-30 09:57:42 -07002411ContentInfo* GetFirstVideoContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002412 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2413}
2414
Steve Anton36b29d12017-10-30 09:57:42 -07002415ContentInfo* GetFirstDataContent(ContentInfos* contents) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002416 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2417}
2418
2419static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2420 MediaType media_type) {
2421 if (sdesc == nullptr) {
2422 return nullptr;
2423 }
2424
Steve Anton36b29d12017-10-30 09:57:42 -07002425 return GetFirstMediaContent(&sdesc->contents(), media_type);
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002426}
2427
2428ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2429 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2430}
2431
2432ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2433 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2434}
2435
2436ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2437 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2438}
2439
2440MediaContentDescription* GetFirstMediaContentDescription(
2441 SessionDescription* sdesc,
2442 MediaType media_type) {
2443 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2444 ContentDescription* description = content ? content->description : NULL;
2445 return static_cast<MediaContentDescription*>(description);
2446}
2447
2448AudioContentDescription* GetFirstAudioContentDescription(
2449 SessionDescription* sdesc) {
2450 return static_cast<AudioContentDescription*>(
2451 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2452}
2453
2454VideoContentDescription* GetFirstVideoContentDescription(
2455 SessionDescription* sdesc) {
2456 return static_cast<VideoContentDescription*>(
2457 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2458}
2459
2460DataContentDescription* GetFirstDataContentDescription(
2461 SessionDescription* sdesc) {
2462 return static_cast<DataContentDescription*>(
2463 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2464}
2465
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002466} // namespace cricket