blob: f6190c2e8f266ba3d6c24ac498b6234b39f9f1ff [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
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010011#include "webrtc/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
jbauchcb560652016-08-04 05:20:32 -070021#include "webrtc/base/base64.h"
nissec80e7412017-01-11 05:56:46 -080022#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000023#include "webrtc/base/helpers.h"
24#include "webrtc/base/logging.h"
deadbeefb7892532017-02-22 19:35:18 -080025#include "webrtc/base/optional.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000026#include "webrtc/base/stringutils.h"
nisse21e4e0b2017-02-20 05:01:01 -080027#include "webrtc/common_types.h"
kjellandera96e2d72016-02-04 23:52:28 -080028#include "webrtc/media/base/cryptoparams.h"
zhihuang38ede132017-06-15 12:52:32 -070029#include "webrtc/media/base/h264_profile_level_id.h"
kjellanderf4752772016-03-02 05:42:30 -080030#include "webrtc/media/base/mediaconstants.h"
31#include "webrtc/p2p/base/p2pconstants.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010032#include "webrtc/pc/channelmanager.h"
33#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
35namespace {
36const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080037
deadbeef7914b8c2017-04-21 03:23:33 -070038void GetSupportedSdesCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
39 std::vector<int>*),
40 const rtc::CryptoOptions& crypto_options,
41 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080042 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070043 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080044 for (const auto crypto : crypto_suites) {
45 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
46 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080047}
terelius8c011e52016-04-26 05:28:11 -070048} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
50namespace cricket {
51
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052// RTP Profile names
53// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
54// RFC4585
55const char kMediaProtocolAvpf[] = "RTP/AVPF";
56// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000057const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
58
deadbeeff3938292015-07-15 12:20:53 -070059// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
60// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061const char kMediaProtocolSavpf[] = "RTP/SAVPF";
62
63const char kMediaProtocolRtpPrefix[] = "RTP/";
64
65const char kMediaProtocolSctp[] = "SCTP";
66const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000067const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000068const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069
deadbeef8b7e9ad2017-05-25 09:38:55 -070070// Note that the below functions support some protocol strings purely for
71// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
72// and Interoperability.
73
74static bool IsDtlsRtp(const std::string& protocol) {
75 // Most-likely values first.
76 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
77 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
78}
79
80static bool IsPlainRtp(const std::string& protocol) {
81 // Most-likely values first.
82 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
83 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
84}
85
86static bool IsDtlsSctp(const std::string& protocol) {
87 return protocol == kMediaProtocolDtlsSctp ||
88 protocol == kMediaProtocolUdpDtlsSctp ||
89 protocol == kMediaProtocolTcpDtlsSctp;
90}
91
92static bool IsPlainSctp(const std::string& protocol) {
93 return protocol == kMediaProtocolSctp;
94}
95
96static bool IsSctp(const std::string& protocol) {
97 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
98}
99
ossu075af922016-06-14 03:29:38 -0700100RtpTransceiverDirection RtpTransceiverDirection::FromMediaContentDirection(
101 MediaContentDirection md) {
102 const bool send = (md == MD_SENDRECV || md == MD_SENDONLY);
103 const bool recv = (md == MD_SENDRECV || md == MD_RECVONLY);
104 return RtpTransceiverDirection(send, recv);
105}
106
107MediaContentDirection RtpTransceiverDirection::ToMediaContentDirection() const {
108 if (send && recv) {
109 return MD_SENDRECV;
110 } else if (send) {
111 return MD_SENDONLY;
112 } else if (recv) {
113 return MD_RECVONLY;
114 }
115
116 return MD_INACTIVE;
117}
118
119RtpTransceiverDirection
120NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
121 RtpTransceiverDirection wants) {
122 return RtpTransceiverDirection(offer.recv && wants.send,
123 offer.send && wants.recv);
124}
125
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126static bool IsMediaContentOfType(const ContentInfo* content,
127 MediaType media_type) {
128 if (!IsMediaContent(content)) {
129 return false;
130 }
131
132 const MediaContentDescription* mdesc =
133 static_cast<const MediaContentDescription*>(content->description);
134 return mdesc && mdesc->type() == media_type;
135}
136
137static bool CreateCryptoParams(int tag, const std::string& cipher,
138 CryptoParams *out) {
jbauchcb560652016-08-04 05:20:32 -0700139 int key_len;
140 int salt_len;
141 if (!rtc::GetSrtpKeyAndSaltLengths(
142 rtc::SrtpCryptoSuiteFromName(cipher), &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143 return false;
144 }
jbauchcb560652016-08-04 05:20:32 -0700145
146 int master_key_len = key_len + salt_len;
147 std::string master_key;
148 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
149 return false;
150 }
151
kwiberg352444f2016-11-28 15:58:53 -0800152 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700153 std::string key = rtc::Base64::Encode(master_key);
154
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 out->tag = tag;
156 out->cipher_suite = cipher;
157 out->key_params = kInline;
158 out->key_params += key;
159 return true;
160}
161
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162static bool AddCryptoParams(const std::string& cipher_suite,
163 CryptoParamsVec *out) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000164 int size = static_cast<int>(out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165
166 out->resize(size + 1);
167 return CreateCryptoParams(size, cipher_suite, &out->at(size));
168}
169
170void AddMediaCryptos(const CryptoParamsVec& cryptos,
171 MediaContentDescription* media) {
172 for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
173 crypto != cryptos.end(); ++crypto) {
174 media->AddCrypto(*crypto);
175 }
176}
177
178bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
179 MediaContentDescription* media) {
180 CryptoParamsVec cryptos;
181 for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
182 it != crypto_suites.end(); ++it) {
183 if (!AddCryptoParams(*it, &cryptos)) {
184 return false;
185 }
186 }
187 AddMediaCryptos(cryptos, media);
188 return true;
189}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190
191const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
192 if (!media) {
193 return NULL;
194 }
195 return &media->cryptos();
196}
197
198bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
199 const CryptoParams& crypto,
200 CryptoParams* out) {
201 for (CryptoParamsVec::const_iterator it = cryptos.begin();
202 it != cryptos.end(); ++it) {
203 if (crypto.Matches(*it)) {
204 *out = *it;
205 return true;
206 }
207 }
208 return false;
209}
210
jbauchcb560652016-08-04 05:20:32 -0700211// For audio, HMAC 32 is prefered over HMAC 80 because of the low overhead.
deadbeef7914b8c2017-04-21 03:23:33 -0700212void GetSupportedAudioSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
213 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700214 if (crypto_options.enable_gcm_crypto_suites) {
215 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
216 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
217 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800218 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
219 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220}
221
deadbeef7914b8c2017-04-21 03:23:33 -0700222void GetSupportedAudioSdesCryptoSuiteNames(
223 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800224 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700225 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
226 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227}
228
deadbeef7914b8c2017-04-21 03:23:33 -0700229void GetSupportedVideoSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
230 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700231 if (crypto_options.enable_gcm_crypto_suites) {
232 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
233 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
234 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800235 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236}
237
deadbeef7914b8c2017-04-21 03:23:33 -0700238void GetSupportedVideoSdesCryptoSuiteNames(
239 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800240 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700241 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
242 crypto_options, crypto_suite_names);
243}
244
245void GetSupportedDataSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
246 std::vector<int>* crypto_suites) {
247 if (crypto_options.enable_gcm_crypto_suites) {
248 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
249 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
250 }
251 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
252}
253
254void GetSupportedDataSdesCryptoSuiteNames(
255 const rtc::CryptoOptions& crypto_options,
256 std::vector<std::string>* crypto_suite_names) {
257 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
258 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800259}
260
jbauchcb560652016-08-04 05:20:32 -0700261// Support any GCM cipher (if enabled through options). For video support only
262// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated unless bundle is enabled
263// because it is low overhead.
264// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265static bool SelectCrypto(const MediaContentDescription* offer,
266 bool bundle,
jbauchcb560652016-08-04 05:20:32 -0700267 const rtc::CryptoOptions& crypto_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268 CryptoParams *crypto) {
269 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
270 const CryptoParamsVec& cryptos = offer->cryptos();
271
272 for (CryptoParamsVec::const_iterator i = cryptos.begin();
273 i != cryptos.end(); ++i) {
jbauchcb560652016-08-04 05:20:32 -0700274 if ((crypto_options.enable_gcm_crypto_suites &&
275 rtc::IsGcmCryptoSuiteName(i->cipher_suite)) ||
276 rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
Guo-wei Shieh456696a2015-09-30 21:48:54 -0700277 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
278 !bundle)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
280 }
281 }
282 return false;
283}
284
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000286// The generated values are added to |ssrcs|.
287// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000289 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200290 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000291 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200292 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000294 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000295 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
297 ssrcs->push_back(candidate);
298 }
299}
300
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301// Finds all StreamParams of all media types and attach them to stream_params.
302static void GetCurrentStreamParams(const SessionDescription* sdesc,
303 StreamParamsVec* stream_params) {
304 if (!sdesc)
305 return;
306
307 const ContentInfos& contents = sdesc->contents();
308 for (ContentInfos::const_iterator content = contents.begin();
309 content != contents.end(); ++content) {
310 if (!IsMediaContent(&*content)) {
311 continue;
312 }
313 const MediaContentDescription* media =
314 static_cast<const MediaContentDescription*>(
315 content->description);
316 const StreamParamsVec& streams = media->streams();
317 for (StreamParamsVec::const_iterator it = streams.begin();
318 it != streams.end(); ++it) {
319 stream_params->push_back(*it);
320 }
321 }
322}
323
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000324// Filters the data codecs for the data channel type.
325void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
326 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700327 const char* codec_name =
328 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000329 for (std::vector<DataCodec>::iterator iter = codecs->begin();
330 iter != codecs->end();) {
solenberg9fa49752016-10-08 13:02:44 -0700331 if (CodecNamesEq(iter->name, codec_name)) {
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000332 iter = codecs->erase(iter);
333 } else {
334 ++iter;
335 }
336 }
337}
338
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339template <typename IdStruct>
340class UsedIds {
341 public:
342 UsedIds(int min_allowed_id, int max_allowed_id)
343 : min_allowed_id_(min_allowed_id),
344 max_allowed_id_(max_allowed_id),
345 next_id_(max_allowed_id) {
346 }
347
348 // Loops through all Id in |ids| and changes its id if it is
349 // already in use by another IdStruct. Call this methods with all Id
350 // in a session description to make sure no duplicate ids exists.
351 // Note that typename Id must be a type of IdStruct.
352 template <typename Id>
353 void FindAndSetIdUsed(std::vector<Id>* ids) {
354 for (typename std::vector<Id>::iterator it = ids->begin();
355 it != ids->end(); ++it) {
356 FindAndSetIdUsed(&*it);
357 }
358 }
359
360 // Finds and sets an unused id if the |idstruct| id is already in use.
361 void FindAndSetIdUsed(IdStruct* idstruct) {
362 const int original_id = idstruct->id;
363 int new_id = idstruct->id;
364
365 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
366 // If the original id is not in range - this is an id that can't be
367 // dynamically changed.
368 return;
369 }
370
371 if (IsIdUsed(original_id)) {
372 new_id = FindUnusedId();
373 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
374 << " to " << new_id;
375 idstruct->id = new_id;
376 }
377 SetIdUsed(new_id);
378 }
379
380 private:
381 // Returns the first unused id in reverse order.
382 // This hopefully reduce the risk of more collisions. We want to change the
383 // default ids as little as possible.
384 int FindUnusedId() {
385 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
386 --next_id_;
387 }
nisseede5da42017-01-12 05:15:36 -0800388 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389 return next_id_;
390 }
391
392 bool IsIdUsed(int new_id) {
393 return id_set_.find(new_id) != id_set_.end();
394 }
395
396 void SetIdUsed(int new_id) {
397 id_set_.insert(new_id);
398 }
399
400 const int min_allowed_id_;
401 const int max_allowed_id_;
402 int next_id_;
403 std::set<int> id_set_;
404};
405
406// Helper class used for finding duplicate RTP payload types among audio, video
407// and data codecs. When bundle is used the payload types may not collide.
408class UsedPayloadTypes : public UsedIds<Codec> {
409 public:
410 UsedPayloadTypes()
411 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
412 }
413
414
415 private:
416 static const int kDynamicPayloadTypeMin = 96;
417 static const int kDynamicPayloadTypeMax = 127;
418};
419
420// Helper class used for finding duplicate RTP Header extension ids among
421// audio and video extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700422class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 public:
424 UsedRtpHeaderExtensionIds()
deadbeefe814a0d2017-02-25 18:15:09 -0800425 : UsedIds<webrtc::RtpExtension>(webrtc::RtpExtension::kMinId,
426 webrtc::RtpExtension::kMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427
428 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429};
430
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431// Adds a StreamParams for each Stream in Streams with media type
432// media_type to content_description.
433// |current_params| - All currently known StreamParams of any media type.
434template <class C>
zhihuang8f65cdf2016-05-06 18:40:30 -0700435static bool AddStreamParams(MediaType media_type,
436 const MediaSessionOptions& options,
437 StreamParamsVec* current_streams,
438 MediaContentDescriptionImpl<C>* content_description,
439 const bool add_legacy_stream) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700440 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700441 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700442 return true;
443 }
444
Noah Richards2e7a0982015-05-18 14:02:54 -0700445 const bool include_rtx_streams =
446 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000447
zhihuang8f65cdf2016-05-06 18:40:30 -0700448 const MediaSessionOptions::Streams& streams = options.streams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 if (streams.empty() && add_legacy_stream) {
450 // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200451 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700452 int num_ssrcs = include_rtx_streams ? 2 : 1;
453 GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
Noah Richards2e7a0982015-05-18 14:02:54 -0700454 if (include_rtx_streams) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
456 content_description->set_multistream(true);
457 } else {
458 content_description->AddLegacyStream(ssrcs[0]);
459 }
460 return true;
461 }
462
brandtr03d5fb12016-11-22 03:37:59 -0800463 const bool include_flexfec_stream =
464 ContainsFlexfecCodec(content_description->codecs());
465
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000466 MediaSessionOptions::Streams::const_iterator stream_it;
467 for (stream_it = streams.begin();
468 stream_it != streams.end(); ++stream_it) {
469 if (stream_it->type != media_type)
470 continue; // Wrong media type.
471
deadbeef2f425aa2017-04-14 10:41:32 -0700472 StreamParams* param = GetStreamByIds(*current_streams, "", stream_it->id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 // groupid is empty for StreamParams generated using
474 // MediaSessionDescriptionFactory.
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000475 if (!param) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 // This is a new stream.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200477 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700478 GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479 StreamParams stream_param;
480 stream_param.id = stream_it->id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000481 // Add the generated ssrc.
482 for (size_t i = 0; i < ssrcs.size(); ++i) {
483 stream_param.ssrcs.push_back(ssrcs[i]);
484 }
485 if (stream_it->num_sim_layers > 1) {
486 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
487 stream_param.ssrc_groups.push_back(group);
488 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700489 // Generate extra ssrcs for include_rtx_streams case.
490 if (include_rtx_streams) {
491 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200492 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700493 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
494 &rtx_ssrcs);
495 for (size_t i = 0; i < ssrcs.size(); ++i) {
496 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
497 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 content_description->set_multistream(true);
499 }
brandtr03d5fb12016-11-22 03:37:59 -0800500 // Generate extra ssrc for include_flexfec_stream case.
501 if (include_flexfec_stream) {
502 // TODO(brandtr): Update when we support multistream protection.
503 if (ssrcs.size() == 1) {
504 std::vector<uint32_t> flexfec_ssrcs;
505 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
506 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
507 content_description->set_multistream(true);
508 } else if (!ssrcs.empty()) {
509 LOG(LS_WARNING)
510 << "Our FlexFEC implementation only supports protecting "
511 << "a single media streams. This session has multiple "
512 << "media streams however, so no FlexFEC SSRC will be generated.";
513 }
514 }
zhihuang8f65cdf2016-05-06 18:40:30 -0700515 stream_param.cname = options.rtcp_cname;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 stream_param.sync_label = stream_it->sync_label;
517 content_description->AddStream(stream_param);
518
519 // Store the new StreamParams in current_streams.
520 // This is necessary so that we can use the CNAME for other media types.
521 current_streams->push_back(stream_param);
522 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700523 // Use existing generated SSRCs/groups, but update the sync_label if
524 // necessary. This may be needed if a MediaStreamTrack was moved from one
525 // MediaStream to another.
526 param->sync_label = stream_it->sync_label;
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000527 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 }
529 }
530 return true;
531}
532
533// Updates the transport infos of the |sdesc| according to the given
534// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800535// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
536// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
538 SessionDescription* sdesc) {
539 // The bundle should not be empty.
540 if (!sdesc || !bundle_group.FirstContentName()) {
541 return false;
542 }
543
544 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700545 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 const TransportInfo* selected_transport_info =
547 sdesc->GetTransportInfoByName(selected_content_name);
548 if (!selected_transport_info) {
549 return false;
550 }
551
552 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700553 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700555 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800557 ConnectionRole selected_connection_role =
558 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 for (TransportInfos::iterator it =
560 sdesc->transport_infos().begin();
561 it != sdesc->transport_infos().end(); ++it) {
562 if (bundle_group.HasContentName(it->content_name) &&
563 it->content_name != selected_content_name) {
564 it->description.ice_ufrag = selected_ufrag;
565 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800566 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 }
568 }
569 return true;
570}
571
572// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
573// sets it to |cryptos|.
574static bool GetCryptosByName(const SessionDescription* sdesc,
575 const std::string& content_name,
576 CryptoParamsVec* cryptos) {
577 if (!sdesc || !cryptos) {
578 return false;
579 }
580
581 const ContentInfo* content = sdesc->GetContentByName(content_name);
582 if (!IsMediaContent(content) || !content->description) {
583 return false;
584 }
585
586 const MediaContentDescription* media_desc =
587 static_cast<const MediaContentDescription*>(content->description);
588 *cryptos = media_desc->cryptos();
589 return true;
590}
591
592// Predicate function used by the remove_if.
593// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
594static bool CryptoNotFound(const CryptoParams crypto,
595 const CryptoParamsVec* filter) {
596 if (filter == NULL) {
597 return true;
598 }
599 for (CryptoParamsVec::const_iterator it = filter->begin();
600 it != filter->end(); ++it) {
601 if (it->cipher_suite == crypto.cipher_suite) {
602 return false;
603 }
604 }
605 return true;
606}
607
608// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
609// which are not available in |filter|.
610static void PruneCryptos(const CryptoParamsVec& filter,
611 CryptoParamsVec* target_cryptos) {
612 if (!target_cryptos) {
613 return;
614 }
615 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
616 target_cryptos->end(),
617 bind2nd(ptr_fun(CryptoNotFound),
618 &filter)),
619 target_cryptos->end());
620}
621
deadbeefb5cb19b2015-11-23 16:39:12 -0800622static bool IsRtpProtocol(const std::string& protocol) {
623 return protocol.empty() ||
624 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
625}
626
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627static bool IsRtpContent(SessionDescription* sdesc,
628 const std::string& content_name) {
629 bool is_rtp = false;
630 ContentInfo* content = sdesc->GetContentByName(content_name);
631 if (IsMediaContent(content)) {
632 MediaContentDescription* media_desc =
633 static_cast<MediaContentDescription*>(content->description);
634 if (!media_desc) {
635 return false;
636 }
deadbeefb5cb19b2015-11-23 16:39:12 -0800637 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 }
639 return is_rtp;
640}
641
642// Updates the crypto parameters of the |sdesc| according to the given
643// |bundle_group|. The crypto parameters of all the contents within the
644// |bundle_group| should be updated to use the common subset of the
645// available cryptos.
646static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
647 SessionDescription* sdesc) {
648 // The bundle should not be empty.
649 if (!sdesc || !bundle_group.FirstContentName()) {
650 return false;
651 }
652
wu@webrtc.org78187522013-10-07 23:32:02 +0000653 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 // Get the common cryptos.
655 const ContentNames& content_names = bundle_group.content_names();
656 CryptoParamsVec common_cryptos;
657 for (ContentNames::const_iterator it = content_names.begin();
658 it != content_names.end(); ++it) {
659 if (!IsRtpContent(sdesc, *it)) {
660 continue;
661 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000662 // The common cryptos are needed if any of the content does not have DTLS
663 // enabled.
664 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
665 common_cryptos_needed = true;
666 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 if (it == content_names.begin()) {
668 // Initial the common_cryptos with the first content in the bundle group.
669 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
670 return false;
671 }
672 if (common_cryptos.empty()) {
673 // If there's no crypto params, we should just return.
674 return true;
675 }
676 } else {
677 CryptoParamsVec cryptos;
678 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
679 return false;
680 }
681 PruneCryptos(cryptos, &common_cryptos);
682 }
683 }
684
wu@webrtc.org78187522013-10-07 23:32:02 +0000685 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 return false;
687 }
688
689 // Update to use the common cryptos.
690 for (ContentNames::const_iterator it = content_names.begin();
691 it != content_names.end(); ++it) {
692 if (!IsRtpContent(sdesc, *it)) {
693 continue;
694 }
695 ContentInfo* content = sdesc->GetContentByName(*it);
696 if (IsMediaContent(content)) {
697 MediaContentDescription* media_desc =
698 static_cast<MediaContentDescription*>(content->description);
699 if (!media_desc) {
700 return false;
701 }
702 media_desc->set_cryptos(common_cryptos);
703 }
704 }
705 return true;
706}
707
708template <class C>
709static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800710 for (const auto& codec : codecs) {
711 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000712 return true;
713 }
714 }
715 return false;
716}
717
718template <class C>
719static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800720 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721}
722
brandtr03d5fb12016-11-22 03:37:59 -0800723template <class C>
724static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
725 for (const auto& codec : codecs) {
726 if (IsFlexfecCodec(codec)) {
727 return true;
728 }
729 }
730 return false;
731}
732
733template <class C>
734static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800735 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800736}
737
deadbeef0ed85b22016-02-23 17:24:52 -0800738static TransportOptions GetTransportOptions(const MediaSessionOptions& options,
739 const std::string& content_name) {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700740 TransportOptions transport_options;
deadbeef0ed85b22016-02-23 17:24:52 -0800741 auto it = options.transport_options.find(content_name);
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700742 if (it != options.transport_options.end()) {
743 transport_options = it->second;
deadbeef0ed85b22016-02-23 17:24:52 -0800744 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700745 transport_options.enable_ice_renomination = options.enable_ice_renomination;
746 return transport_options;
deadbeef0ed85b22016-02-23 17:24:52 -0800747}
748
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749// Create a media content to be offered in a session-initiate,
750// according to the given options.rtcp_mux, options.is_muc,
751// options.streams, codecs, secure_transport, crypto, and streams. If we don't
752// currently have crypto (in current_cryptos) and it is enabled (in
753// secure_policy), crypto is created (according to crypto_suites). If
754// add_legacy_stream is true, and current_streams is empty, a legacy
755// stream is created. The created content is added to the offer.
756template <class C>
757static bool CreateMediaContentOffer(
758 const MediaSessionOptions& options,
759 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000760 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 const CryptoParamsVec* current_cryptos,
762 const std::vector<std::string>& crypto_suites,
763 const RtpHeaderExtensions& rtp_extensions,
764 bool add_legacy_stream,
765 StreamParamsVec* current_streams,
766 MediaContentDescriptionImpl<C>* offer) {
767 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 offer->set_rtcp_mux(options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700770 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
771 offer->set_rtcp_reduced_size(true);
772 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 offer->set_multistream(options.is_muc);
774 offer->set_rtp_header_extensions(rtp_extensions);
775
zhihuang8f65cdf2016-05-06 18:40:30 -0700776 if (!AddStreamParams(offer->type(), options, current_streams, offer,
777 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 return false;
779 }
780
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 if (secure_policy != SEC_DISABLED) {
782 if (current_cryptos) {
783 AddMediaCryptos(*current_cryptos, offer);
784 }
785 if (offer->cryptos().empty()) {
786 if (!CreateMediaCryptos(crypto_suites, offer)) {
787 return false;
788 }
789 }
790 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791
deadbeef7af91dd2016-12-13 11:29:11 -0800792 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 return false;
794 }
795 return true;
796}
797
798template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000799static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800800 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000801 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800802 const int codec2_id) {
803 const C* codec1 = FindCodecById(codecs1, codec1_id);
804 const C* codec2 = FindCodecById(codecs2, codec2_id);
805 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000806}
807
808template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809static void NegotiateCodecs(const std::vector<C>& local_codecs,
810 const std::vector<C>& offered_codecs,
811 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800812 for (const C& ours : local_codecs) {
813 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700814 // Note that we intentionally only find one matching codec for each of our
815 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800816 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
817 C negotiated = ours;
818 negotiated.IntersectFeedbackParams(theirs);
819 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800820 const auto apt_it =
821 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800822 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800823 RTC_DCHECK(apt_it != theirs.params.end());
824 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 }
magjedf823ede2016-11-12 09:53:04 -0800826 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
827 webrtc::H264::GenerateProfileLevelIdForAnswer(
828 ours.params, theirs.params, &negotiated.params);
829 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800830 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700831 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800832 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 }
834 }
deadbeef67cf2c12016-04-13 10:07:16 -0700835 // RFC3264: Although the answerer MAY list the formats in their desired
836 // order of preference, it is RECOMMENDED that unless there is a
837 // specific reason, the answerer list formats in the same relative order
838 // they were present in the offer.
839 std::unordered_map<int, int> payload_type_preferences;
840 int preference = static_cast<int>(offered_codecs.size() + 1);
841 for (const C& codec : offered_codecs) {
842 payload_type_preferences[codec.id] = preference--;
843 }
844 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
845 [&payload_type_preferences](const C& a, const C& b) {
846 return payload_type_preferences[a.id] >
847 payload_type_preferences[b.id];
848 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849}
850
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800851// Finds a codec in |codecs2| that matches |codec_to_match|, which is
852// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
853// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800855static bool FindMatchingCodec(const std::vector<C>& codecs1,
856 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 const C& codec_to_match,
858 C* found_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800859 for (const C& potential_match : codecs2) {
860 if (potential_match.Matches(codec_to_match)) {
861 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800862 int apt_value_1 = 0;
863 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800864 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
865 &apt_value_1) ||
866 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
867 &apt_value_2)) {
868 LOG(LS_WARNING) << "RTX missing associated payload type.";
869 continue;
870 }
871 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
872 apt_value_2)) {
873 continue;
874 }
875 }
876 if (found_codec) {
877 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 }
879 return true;
880 }
881 }
882 return false;
883}
884
885// Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
886// already exist in |offered_codecs| and ensure the payload types don't
887// collide.
888template <class C>
889static void FindCodecsToOffer(
890 const std::vector<C>& reference_codecs,
891 std::vector<C>* offered_codecs,
892 UsedPayloadTypes* used_pltypes) {
893
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;
911
912 std::string associated_pt_str;
913 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
914 &associated_pt_str)) {
915 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
916 << " is missing an associated payload type.";
917 continue;
918 }
919
920 int associated_pt;
921 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
922 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
923 << " of RTX codec " << rtx_codec.name
924 << " to an integer.";
925 continue;
926 }
927
928 // Find the associated reference codec for the reference RTX codec.
magjedb05fa242016-11-11 04:00:16 -0800929 const C* associated_codec =
930 FindCodecById(reference_codecs, associated_pt);
931 if (!associated_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800932 LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
933 << associated_pt << " for RTX codec " << rtx_codec.name
934 << ".";
935 continue;
936 }
937
938 // Find a codec in the offered list that matches the reference codec.
939 // Its payload type may be different than the reference codec.
940 C matching_codec;
941 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800942 *associated_codec, &matching_codec)) {
943 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800944 << " codec.";
945 continue;
946 }
947
948 rtx_codec.params[kCodecParamAssociatedPayloadType] =
949 rtc::ToString(matching_codec.id);
950 used_pltypes->FindAndSetIdUsed(&rtx_codec);
951 offered_codecs->push_back(rtx_codec);
952 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953 }
954}
955
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700957 const webrtc::RtpExtension& ext_to_match,
958 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700959 // We assume that all URIs are given in a canonical format.
960 const webrtc::RtpExtension* found =
961 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
962 ext_to_match.uri);
963 if (!found) {
964 return false;
965 }
966 if (found_extension) {
967 *found_extension = *found;
968 }
969 return true;
970}
971
972static bool FindByUriWithEncryptionPreference(
973 const RtpHeaderExtensions& extensions,
974 const webrtc::RtpExtension& ext_to_match, bool encryption_preference,
975 webrtc::RtpExtension* found_extension) {
976 const webrtc::RtpExtension* unencrypted_extension = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
978 it != extensions.end(); ++it) {
979 // We assume that all URIs are given in a canonical format.
980 if (it->uri == ext_to_match.uri) {
jbauch5869f502017-06-29 12:31:36 -0700981 if (!encryption_preference || it->encrypt) {
982 if (found_extension) {
983 *found_extension = *it;
984 }
985 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 }
jbauch5869f502017-06-29 12:31:36 -0700987 unencrypted_extension = &(*it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 }
989 }
jbauch5869f502017-06-29 12:31:36 -0700990 if (unencrypted_extension) {
991 if (found_extension) {
992 *found_extension = *unencrypted_extension;
993 }
994 return true;
995 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 return false;
997}
998
jbauch5869f502017-06-29 12:31:36 -0700999// Iterates through |offered_extensions|, adding each one to
1000// |regular_extensions| (or |encrypted_extensions| if encrypted) and |used_ids|,
1001// and resolving ID conflicts.
1002// If an offered extension has the same URI as one in |regular_extensions| or
1003// |encrypted_extensions|, it will re-use the same ID and won't be treated as
1004// a conflict.
deadbeefa5b273a2015-08-20 17:30:13 -07001005static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001006 RtpHeaderExtensions* regular_extensions,
1007 RtpHeaderExtensions* encrypted_extensions,
deadbeefa5b273a2015-08-20 17:30:13 -07001008 UsedRtpHeaderExtensionIds* used_ids) {
1009 for (auto& extension : *offered_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -07001010 webrtc::RtpExtension existing;
jbauch5869f502017-06-29 12:31:36 -07001011 if ((extension.encrypt &&
1012 FindByUri(*encrypted_extensions, extension, &existing)) ||
1013 (!extension.encrypt &&
1014 FindByUri(*regular_extensions, extension, &existing))) {
deadbeefa5b273a2015-08-20 17:30:13 -07001015 extension.id = existing.id;
1016 } else {
1017 used_ids->FindAndSetIdUsed(&extension);
jbauch5869f502017-06-29 12:31:36 -07001018 if (extension.encrypt) {
1019 encrypted_extensions->push_back(extension);
1020 } else {
1021 regular_extensions->push_back(extension);
1022 }
deadbeefa5b273a2015-08-20 17:30:13 -07001023 }
1024 }
1025}
1026
1027// Adds |reference_extensions| to |offered_extensions|, while updating
1028// |all_extensions| and |used_ids|.
1029static void FindRtpHdrExtsToOffer(
1030 const RtpHeaderExtensions& reference_extensions,
1031 RtpHeaderExtensions* offered_extensions,
1032 RtpHeaderExtensions* all_extensions,
1033 UsedRtpHeaderExtensionIds* used_ids) {
1034 for (auto reference_extension : reference_extensions) {
1035 if (!FindByUri(*offered_extensions, reference_extension, NULL)) {
isheriff6f8d6862016-05-26 11:24:55 -07001036 webrtc::RtpExtension existing;
deadbeefa5b273a2015-08-20 17:30:13 -07001037 if (FindByUri(*all_extensions, reference_extension, &existing)) {
1038 offered_extensions->push_back(existing);
1039 } else {
1040 used_ids->FindAndSetIdUsed(&reference_extension);
1041 all_extensions->push_back(reference_extension);
1042 offered_extensions->push_back(reference_extension);
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001043 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 }
1045 }
1046}
1047
jbauch5869f502017-06-29 12:31:36 -07001048static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1049 RtpHeaderExtensions* all_extensions,
1050 UsedRtpHeaderExtensionIds* used_ids) {
1051 RtpHeaderExtensions encrypted_extensions;
1052 for (const webrtc::RtpExtension& extension : *extensions) {
1053 webrtc::RtpExtension existing;
1054 // Don't add encrypted extensions again that were already included in a
1055 // previous offer or regular extensions that are also included as encrypted
1056 // extensions.
1057 if (extension.encrypt ||
1058 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1059 (FindByUriWithEncryptionPreference(*extensions, extension, true,
1060 &existing) && existing.encrypt)) {
1061 continue;
1062 }
1063
1064 if (FindByUri(*all_extensions, extension, &existing)) {
1065 encrypted_extensions.push_back(existing);
1066 } else {
1067 webrtc::RtpExtension encrypted(extension);
1068 encrypted.encrypt = true;
1069 used_ids->FindAndSetIdUsed(&encrypted);
1070 all_extensions->push_back(encrypted);
1071 encrypted_extensions.push_back(encrypted);
1072 }
1073 }
1074 extensions->insert(extensions->end(), encrypted_extensions.begin(),
1075 encrypted_extensions.end());
1076}
1077
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078static void NegotiateRtpHeaderExtensions(
1079 const RtpHeaderExtensions& local_extensions,
1080 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001081 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 RtpHeaderExtensions* negotiated_extenstions) {
1083 RtpHeaderExtensions::const_iterator ours;
1084 for (ours = local_extensions.begin();
1085 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 11:24:55 -07001086 webrtc::RtpExtension theirs;
jbauch5869f502017-06-29 12:31:36 -07001087 if (FindByUriWithEncryptionPreference(offered_extensions, *ours,
1088 enable_encrypted_rtp_header_extensions, &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001089 // We respond with their RTP header extension id.
1090 negotiated_extenstions->push_back(theirs);
1091 }
1092 }
1093}
1094
1095static void StripCNCodecs(AudioCodecs* audio_codecs) {
1096 AudioCodecs::iterator iter = audio_codecs->begin();
1097 while (iter != audio_codecs->end()) {
nisse21e4e0b2017-02-20 05:01:01 -08001098 if (STR_CASE_CMP(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099 iter = audio_codecs->erase(iter);
1100 } else {
1101 ++iter;
1102 }
1103 }
1104}
1105
1106// Create a media content to be answered in a session-accept,
1107// according to the given options.rtcp_mux, options.streams, codecs,
1108// crypto, and streams. If we don't currently have crypto (in
1109// current_cryptos) and it is enabled (in secure_policy), crypto is
1110// created (according to crypto_suites). If add_legacy_stream is
1111// true, and current_streams is empty, a legacy stream is created.
1112// The codecs, rtcp_mux, and crypto are all negotiated with the offer
1113// from the incoming session-initiate. If the negotiation fails, this
1114// method returns false. The created content is added to the offer.
1115template <class C>
1116static bool CreateMediaContentAnswer(
1117 const MediaContentDescriptionImpl<C>* offer,
1118 const MediaSessionOptions& options,
1119 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001120 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001121 const CryptoParamsVec* current_cryptos,
1122 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001123 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 StreamParamsVec* current_streams,
1125 bool add_legacy_stream,
1126 bool bundle_enabled,
1127 MediaContentDescriptionImpl<C>* answer) {
1128 std::vector<C> negotiated_codecs;
1129 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1130 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 answer->set_protocol(offer->protocol());
1132 RtpHeaderExtensions negotiated_rtp_extensions;
1133 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1134 offer->rtp_header_extensions(),
jbauch5869f502017-06-29 12:31:36 -07001135 enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 &negotiated_rtp_extensions);
1137 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1138
1139 answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001140 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1141 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1142 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143
1144 if (sdes_policy != SEC_DISABLED) {
1145 CryptoParams crypto;
jbauchcb560652016-08-04 05:20:32 -07001146 if (SelectCrypto(offer, bundle_enabled, options.crypto_options, &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147 if (current_cryptos) {
1148 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1149 }
1150 answer->AddCrypto(crypto);
1151 }
1152 }
1153
deadbeef7af91dd2016-12-13 11:29:11 -08001154 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 return false;
1156 }
1157
zhihuang8f65cdf2016-05-06 18:40:30 -07001158 if (!AddStreamParams(answer->type(), options, current_streams, answer,
1159 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160 return false; // Something went seriously wrong.
1161 }
1162
1163 // Make sure the answer media content direction is per default set as
1164 // described in RFC3264 section 6.1.
ossu075af922016-06-14 03:29:38 -07001165 const bool is_data = !IsRtpProtocol(answer->protocol());
1166 const bool has_send_streams = !answer->streams().empty();
1167 const bool wants_send = has_send_streams || is_data;
1168 const bool recv_audio =
1169 answer->type() == cricket::MEDIA_TYPE_AUDIO && options.recv_audio;
1170 const bool recv_video =
1171 answer->type() == cricket::MEDIA_TYPE_VIDEO && options.recv_video;
1172 const bool recv_data =
1173 answer->type() == cricket::MEDIA_TYPE_DATA;
1174 const bool wants_receive = recv_audio || recv_video || recv_data;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175
ossu075af922016-06-14 03:29:38 -07001176 auto offer_rtd =
1177 RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
1178 auto wants_rtd = RtpTransceiverDirection(wants_send, wants_receive);
1179 answer->set_direction(NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd)
1180 .ToMediaContentDirection());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 return true;
1182}
1183
1184static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001185 const std::string& protocol,
1186 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001187 // Since not all applications serialize and deserialize the media protocol,
1188 // we will have to accept |protocol| to be empty.
1189 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 return true;
1191 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001192
zhihuangcf5b37c2016-05-05 11:44:35 -07001193 if (type == MEDIA_TYPE_DATA) {
1194 // Check for SCTP, but also for RTP for RTP-based data channels.
1195 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1196 if (secure_transport) {
1197 // Most likely scenarios first.
1198 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1199 IsPlainRtp(protocol);
1200 } else {
1201 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1202 }
1203 }
1204
1205 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1206 // JSEP specifies.
1207 if (secure_transport) {
1208 // Most likely scenarios first.
1209 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1210 } else {
1211 return IsPlainRtp(protocol);
1212 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213}
1214
1215static void SetMediaProtocol(bool secure_transport,
1216 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001217 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001219 else if (secure_transport)
1220 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 else
1222 desc->set_protocol(kMediaProtocolAvpf);
1223}
1224
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001225// Gets the TransportInfo of the given |content_name| from the
1226// |current_description|. If doesn't exist, returns a new one.
1227static const TransportDescription* GetTransportDescription(
1228 const std::string& content_name,
1229 const SessionDescription* current_description) {
1230 const TransportDescription* desc = NULL;
1231 if (current_description) {
1232 const TransportInfo* info =
1233 current_description->GetTransportInfoByName(content_name);
1234 if (info) {
1235 desc = &info->description;
1236 }
1237 }
1238 return desc;
1239}
1240
1241// Gets the current DTLS state from the transport description.
1242static bool IsDtlsActive(
1243 const std::string& content_name,
1244 const SessionDescription* current_description) {
1245 if (!current_description)
1246 return false;
1247
1248 const ContentInfo* content =
1249 current_description->GetContentByName(content_name);
1250 if (!content)
1251 return false;
1252
1253 const TransportDescription* current_tdesc =
1254 GetTransportDescription(content_name, current_description);
1255 if (!current_tdesc)
1256 return false;
1257
1258 return current_tdesc->secure();
1259}
1260
ossu075af922016-06-14 03:29:38 -07001261std::string MediaContentDirectionToString(MediaContentDirection direction) {
1262 std::string dir_str;
1263 switch (direction) {
1264 case MD_INACTIVE:
1265 dir_str = "inactive";
1266 break;
1267 case MD_SENDONLY:
1268 dir_str = "sendonly";
1269 break;
1270 case MD_RECVONLY:
1271 dir_str = "recvonly";
1272 break;
1273 case MD_SENDRECV:
1274 dir_str = "sendrecv";
1275 break;
1276 default:
nissec80e7412017-01-11 05:56:46 -08001277 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07001278 break;
1279 }
1280
1281 return dir_str;
1282}
1283
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001284void MediaSessionOptions::AddSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285 const std::string& id,
1286 const std::string& sync_label) {
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001287 AddSendStreamInternal(type, id, sync_label, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001288}
1289
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001290void MediaSessionOptions::AddSendVideoStream(
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001291 const std::string& id,
1292 const std::string& sync_label,
1293 int num_sim_layers) {
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001294 AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001295}
1296
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001297void MediaSessionOptions::AddSendStreamInternal(
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001298 MediaType type,
1299 const std::string& id,
1300 const std::string& sync_label,
1301 int num_sim_layers) {
1302 streams.push_back(Stream(type, id, sync_label, num_sim_layers));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304 // If we haven't already set the data_channel_type, and we add a
1305 // stream, we assume it's an RTP data stream.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001306 if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 data_channel_type = DCT_RTP;
1308}
1309
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001310void MediaSessionOptions::RemoveSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 const std::string& id) {
1312 Streams::iterator stream_it = streams.begin();
1313 for (; stream_it != streams.end(); ++stream_it) {
1314 if (stream_it->type == type && stream_it->id == id) {
1315 streams.erase(stream_it);
1316 return;
1317 }
1318 }
nissec80e7412017-01-11 05:56:46 -08001319 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320}
1321
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001322bool MediaSessionOptions::HasSendMediaStream(MediaType type) const {
1323 Streams::const_iterator stream_it = streams.begin();
1324 for (; stream_it != streams.end(); ++stream_it) {
1325 if (stream_it->type == type) {
1326 return true;
1327 }
1328 }
1329 return false;
1330}
1331
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1333 const TransportDescriptionFactory* transport_desc_factory)
1334 : secure_(SEC_DISABLED),
1335 add_legacy_(true),
1336 transport_desc_factory_(transport_desc_factory) {
1337}
1338
1339MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1340 ChannelManager* channel_manager,
1341 const TransportDescriptionFactory* transport_desc_factory)
1342 : secure_(SEC_DISABLED),
1343 add_legacy_(true),
1344 transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001345 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1346 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001348 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1350 channel_manager->GetSupportedDataCodecs(&data_codecs_);
ossudedfd282016-06-14 07:12:39 -07001351 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
1352 &audio_sendrecv_codecs_);
ossu075af922016-06-14 03:29:38 -07001353}
1354
ossudedfd282016-06-14 07:12:39 -07001355const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1356 const {
ossu075af922016-06-14 03:29:38 -07001357 return audio_sendrecv_codecs_;
1358}
1359
1360const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1361 return audio_send_codecs_;
1362}
1363
1364const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1365 return audio_recv_codecs_;
1366}
1367
1368void MediaSessionDescriptionFactory::set_audio_codecs(
1369 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1370 audio_send_codecs_ = send_codecs;
1371 audio_recv_codecs_ = recv_codecs;
1372 audio_sendrecv_codecs_.clear();
1373 // Use NegotiateCodecs to merge our codec lists, since the operation is
1374 // essentially the same. Put send_codecs as the offered_codecs, which is the
1375 // order we'd like to follow. The reasoning is that encoding is usually more
1376 // expensive than decoding, and prioritizing a codec in the send list probably
1377 // means it's a codec we can handle efficiently.
1378 NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001379}
1380
1381SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
1382 const MediaSessionOptions& options,
1383 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001384 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001385
1386 StreamParamsVec current_streams;
1387 GetCurrentStreamParams(current_description, &current_streams);
1388
ossu075af922016-06-14 03:29:38 -07001389 const bool wants_send =
1390 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1391 const AudioCodecs& supported_audio_codecs =
1392 GetAudioCodecsForOffer({wants_send, options.recv_audio});
1393
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394 AudioCodecs audio_codecs;
1395 VideoCodecs video_codecs;
1396 DataCodecs data_codecs;
ossu075af922016-06-14 03:29:38 -07001397 GetCodecsToOffer(current_description, supported_audio_codecs,
1398 video_codecs_, data_codecs_,
1399 &audio_codecs, &video_codecs, &data_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001400
1401 if (!options.vad_enabled) {
1402 // If application doesn't want CN codecs in offer.
1403 StripCNCodecs(&audio_codecs);
1404 }
1405
1406 RtpHeaderExtensions audio_rtp_extensions;
1407 RtpHeaderExtensions video_rtp_extensions;
1408 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1409 &video_rtp_extensions);
1410
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001411 bool audio_added = false;
1412 bool video_added = false;
1413 bool data_added = false;
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001414
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001415 // Iterate through the contents of |current_description| to maintain the order
1416 // of the m-lines in the new offer.
1417 if (current_description) {
1418 ContentInfos::const_iterator it = current_description->contents().begin();
1419 for (; it != current_description->contents().end(); ++it) {
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001420 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001421 if (!AddAudioContentForOffer(options, current_description,
1422 audio_rtp_extensions, audio_codecs,
1423 &current_streams, offer.get())) {
1424 return NULL;
1425 }
1426 audio_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001427 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001428 if (!AddVideoContentForOffer(options, current_description,
1429 video_rtp_extensions, video_codecs,
1430 &current_streams, offer.get())) {
1431 return NULL;
1432 }
1433 video_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001434 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) {
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001435 MediaSessionOptions options_copy(options);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001436 if (IsSctp(static_cast<const MediaContentDescription*>(it->description)
1437 ->protocol())) {
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001438 options_copy.data_channel_type = DCT_SCTP;
1439 }
1440 if (!AddDataContentForOffer(options_copy, current_description,
1441 &data_codecs, &current_streams,
1442 offer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001443 return NULL;
1444 }
1445 data_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001446 } else {
nissec80e7412017-01-11 05:56:46 -08001447 RTC_NOTREACHED();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001448 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001449 }
1450 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001451
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001452 // Append contents that are not in |current_description|.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001453 if (!audio_added && options.has_audio() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001454 !AddAudioContentForOffer(options, current_description,
1455 audio_rtp_extensions, audio_codecs,
1456 &current_streams, offer.get())) {
1457 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001458 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001459 if (!video_added && options.has_video() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001460 !AddVideoContentForOffer(options, current_description,
1461 video_rtp_extensions, video_codecs,
1462 &current_streams, offer.get())) {
1463 return NULL;
1464 }
1465 if (!data_added && options.has_data() &&
1466 !AddDataContentForOffer(options, current_description, &data_codecs,
1467 &current_streams, offer.get())) {
1468 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469 }
1470
1471 // Bundle the contents together, if we've been asked to do so, and update any
1472 // parameters that need to be tweaked for BUNDLE.
1473 if (options.bundle_enabled) {
1474 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
1475 for (ContentInfos::const_iterator content = offer->contents().begin();
1476 content != offer->contents().end(); ++content) {
1477 offer_bundle.AddContentName(content->name);
1478 }
1479 offer->AddGroup(offer_bundle);
1480 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1481 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
1482 return NULL;
1483 }
1484 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1485 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1486 return NULL;
1487 }
1488 }
1489
1490 return offer.release();
1491}
1492
1493SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
1494 const SessionDescription* offer, const MediaSessionOptions& options,
1495 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001496 if (!offer) {
1497 return nullptr;
1498 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001500 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1501 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001502 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001503
1504 StreamParamsVec current_streams;
1505 GetCurrentStreamParams(current_description, &current_streams);
1506
deadbeefb7892532017-02-22 19:35:18 -08001507 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1508 // group in the answer with the appropriate content names.
1509 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1510 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1511 // Transport info shared by the bundle group.
1512 std::unique_ptr<TransportInfo> bundle_transport;
1513
1514 ContentInfos::const_iterator it = offer->contents().begin();
1515 for (; it != offer->contents().end(); ++it) {
1516 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
1517 if (!AddAudioContentForAnswer(offer, options, current_description,
1518 bundle_transport.get(), &current_streams,
1519 answer.get())) {
1520 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521 }
deadbeefb7892532017-02-22 19:35:18 -08001522 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
1523 if (!AddVideoContentForAnswer(offer, options, current_description,
1524 bundle_transport.get(), &current_streams,
1525 answer.get())) {
1526 return NULL;
1527 }
1528 } else {
1529 RTC_DCHECK(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA));
1530 if (!AddDataContentForAnswer(offer, options, current_description,
1531 bundle_transport.get(), &current_streams,
1532 answer.get())) {
1533 return NULL;
1534 }
1535 }
1536 // See if we can add the newly generated m= section to the BUNDLE group in
1537 // the answer.
1538 ContentInfo& added = answer->contents().back();
1539 if (!added.rejected && options.bundle_enabled && offer_bundle &&
1540 offer_bundle->HasContentName(added.name)) {
1541 answer_bundle.AddContentName(added.name);
1542 bundle_transport.reset(
1543 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001544 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545 }
1546
deadbeefb7892532017-02-22 19:35:18 -08001547 // Only put BUNDLE group in answer if nonempty.
1548 if (answer_bundle.FirstContentName()) {
1549 answer->AddGroup(answer_bundle);
1550
1551 // Share the same ICE credentials and crypto params across all contents,
1552 // as BUNDLE requires.
1553 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1554 LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1555 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001556 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001557
deadbeefb7892532017-02-22 19:35:18 -08001558 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1559 LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1560 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561 }
1562 }
1563
1564 return answer.release();
1565}
1566
ossu075af922016-06-14 03:29:38 -07001567const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1568 const RtpTransceiverDirection& direction) const {
1569 // If stream is inactive - generate list as if sendrecv.
1570 if (direction.send == direction.recv) {
1571 return audio_sendrecv_codecs_;
1572 } else if (direction.send) {
1573 return audio_send_codecs_;
1574 } else {
1575 return audio_recv_codecs_;
1576 }
1577}
1578
1579const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1580 const RtpTransceiverDirection& offer,
1581 const RtpTransceiverDirection& answer) const {
1582 // For inactive and sendrecv answers, generate lists as if we were to accept
1583 // the offer's direction. See RFC 3264 Section 6.1.
1584 if (answer.send == answer.recv) {
1585 if (offer.send == offer.recv) {
1586 return audio_sendrecv_codecs_;
1587 } else if (offer.send) {
1588 return audio_recv_codecs_;
1589 } else {
1590 return audio_send_codecs_;
1591 }
1592 } else if (answer.send) {
1593 return audio_send_codecs_;
1594 } else {
1595 return audio_recv_codecs_;
1596 }
1597}
1598
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599void MediaSessionDescriptionFactory::GetCodecsToOffer(
1600 const SessionDescription* current_description,
ossu075af922016-06-14 03:29:38 -07001601 const AudioCodecs& supported_audio_codecs,
1602 const VideoCodecs& supported_video_codecs,
1603 const DataCodecs& supported_data_codecs,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604 AudioCodecs* audio_codecs,
1605 VideoCodecs* video_codecs,
1606 DataCodecs* data_codecs) const {
1607 UsedPayloadTypes used_pltypes;
1608 audio_codecs->clear();
1609 video_codecs->clear();
1610 data_codecs->clear();
1611
1612
1613 // First - get all codecs from the current description if the media type
1614 // is used.
1615 // Add them to |used_pltypes| so the payloadtype is not reused if a new media
1616 // type is added.
1617 if (current_description) {
1618 const AudioContentDescription* audio =
1619 GetFirstAudioContentDescription(current_description);
1620 if (audio) {
1621 *audio_codecs = audio->codecs();
1622 used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
1623 }
1624 const VideoContentDescription* video =
1625 GetFirstVideoContentDescription(current_description);
1626 if (video) {
1627 *video_codecs = video->codecs();
1628 used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
1629 }
1630 const DataContentDescription* data =
1631 GetFirstDataContentDescription(current_description);
1632 if (data) {
1633 *data_codecs = data->codecs();
1634 used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
1635 }
1636 }
1637
1638 // Add our codecs that are not in |current_description|.
ossu075af922016-06-14 03:29:38 -07001639 FindCodecsToOffer<AudioCodec>(supported_audio_codecs, audio_codecs,
1640 &used_pltypes);
1641 FindCodecsToOffer<VideoCodec>(supported_video_codecs, video_codecs,
1642 &used_pltypes);
1643 FindCodecsToOffer<DataCodec>(supported_data_codecs, data_codecs,
1644 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645}
1646
1647void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1648 const SessionDescription* current_description,
1649 RtpHeaderExtensions* audio_extensions,
1650 RtpHeaderExtensions* video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001651 // All header extensions allocated from the same range to avoid potential
1652 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001653 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001654 RtpHeaderExtensions all_regular_extensions;
1655 RtpHeaderExtensions all_encrypted_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656 audio_extensions->clear();
1657 video_extensions->clear();
1658
1659 // First - get all extensions from the current description if the media type
1660 // is used.
1661 // Add them to |used_ids| so the local ids are not reused if a new media
1662 // type is added.
1663 if (current_description) {
1664 const AudioContentDescription* audio =
1665 GetFirstAudioContentDescription(current_description);
1666 if (audio) {
1667 *audio_extensions = audio->rtp_header_extensions();
jbauch5869f502017-06-29 12:31:36 -07001668 FindAndSetRtpHdrExtUsed(audio_extensions, &all_regular_extensions,
1669 &all_encrypted_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001670 }
1671 const VideoContentDescription* video =
1672 GetFirstVideoContentDescription(current_description);
1673 if (video) {
1674 *video_extensions = video->rtp_header_extensions();
jbauch5869f502017-06-29 12:31:36 -07001675 FindAndSetRtpHdrExtUsed(video_extensions, &all_regular_extensions,
1676 &all_encrypted_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001677 }
1678 }
1679
1680 // Add our default RTP header extensions that are not in
1681 // |current_description|.
deadbeefa5b273a2015-08-20 17:30:13 -07001682 FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions,
jbauch5869f502017-06-29 12:31:36 -07001683 &all_regular_extensions, &used_ids);
deadbeefa5b273a2015-08-20 17:30:13 -07001684 FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions,
jbauch5869f502017-06-29 12:31:36 -07001685 &all_regular_extensions, &used_ids);
1686 // TODO(jbauch): Support adding encrypted header extensions to existing
1687 // sessions.
1688 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
1689 AddEncryptedVersionsOfHdrExts(audio_extensions, &all_encrypted_extensions,
1690 &used_ids);
1691 AddEncryptedVersionsOfHdrExts(video_extensions, &all_encrypted_extensions,
1692 &used_ids);
1693 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001694}
1695
1696bool MediaSessionDescriptionFactory::AddTransportOffer(
1697 const std::string& content_name,
1698 const TransportOptions& transport_options,
1699 const SessionDescription* current_desc,
1700 SessionDescription* offer_desc) const {
1701 if (!transport_desc_factory_)
1702 return false;
1703 const TransportDescription* current_tdesc =
1704 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001705 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1707 bool ret = (new_tdesc.get() != NULL &&
1708 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1709 if (!ret) {
1710 LOG(LS_ERROR)
1711 << "Failed to AddTransportOffer, content name=" << content_name;
1712 }
1713 return ret;
1714}
1715
1716TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1717 const std::string& content_name,
1718 const SessionDescription* offer_desc,
1719 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001720 const SessionDescription* current_desc,
1721 bool require_transport_attributes) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722 if (!transport_desc_factory_)
1723 return NULL;
1724 const TransportDescription* offer_tdesc =
1725 GetTransportDescription(content_name, offer_desc);
1726 const TransportDescription* current_tdesc =
1727 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001728 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1729 require_transport_attributes,
1730 current_tdesc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731}
1732
1733bool MediaSessionDescriptionFactory::AddTransportAnswer(
1734 const std::string& content_name,
1735 const TransportDescription& transport_desc,
1736 SessionDescription* answer_desc) const {
1737 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1738 transport_desc))) {
1739 LOG(LS_ERROR)
1740 << "Failed to AddTransportAnswer, content name=" << content_name;
1741 return false;
1742 }
1743 return true;
1744}
1745
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001746bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
1747 const MediaSessionOptions& options,
1748 const SessionDescription* current_description,
1749 const RtpHeaderExtensions& audio_rtp_extensions,
1750 const AudioCodecs& audio_codecs,
1751 StreamParamsVec* current_streams,
1752 SessionDescription* desc) const {
deadbeef44f08192015-12-15 16:20:09 -08001753 const ContentInfo* current_audio_content =
1754 GetFirstAudioContent(current_description);
1755 std::string content_name =
1756 current_audio_content ? current_audio_content->name : CN_AUDIO;
1757
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001758 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001759 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1760 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001761
kwiberg31022942016-03-11 14:18:21 -08001762 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001763 std::vector<std::string> crypto_suites;
deadbeef7914b8c2017-04-21 03:23:33 -07001764 GetSupportedAudioSdesCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001765 if (!CreateMediaContentOffer(
1766 options,
1767 audio_codecs,
1768 sdes_policy,
1769 GetCryptos(GetFirstAudioContentDescription(current_description)),
1770 crypto_suites,
1771 audio_rtp_extensions,
1772 add_legacy_,
1773 current_streams,
1774 audio.get())) {
1775 return false;
1776 }
1777 audio->set_lang(lang_);
1778
1779 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1780 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001781
ossu075af922016-06-14 03:29:38 -07001782 auto offer_rtd =
1783 RtpTransceiverDirection(!audio->streams().empty(), options.recv_audio);
1784 audio->set_direction(offer_rtd.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001785
deadbeef44f08192015-12-15 16:20:09 -08001786 desc->AddContent(content_name, NS_JINGLE_RTP, audio.release());
deadbeef0ed85b22016-02-23 17:24:52 -08001787 if (!AddTransportOffer(content_name,
1788 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001789 current_description, desc)) {
1790 return false;
1791 }
1792
1793 return true;
1794}
1795
1796bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
1797 const MediaSessionOptions& options,
1798 const SessionDescription* current_description,
1799 const RtpHeaderExtensions& video_rtp_extensions,
1800 const VideoCodecs& video_codecs,
1801 StreamParamsVec* current_streams,
1802 SessionDescription* desc) const {
deadbeef44f08192015-12-15 16:20:09 -08001803 const ContentInfo* current_video_content =
1804 GetFirstVideoContent(current_description);
1805 std::string content_name =
1806 current_video_content ? current_video_content->name : CN_VIDEO;
1807
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001808 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001809 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1810 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001811
kwiberg31022942016-03-11 14:18:21 -08001812 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001813 std::vector<std::string> crypto_suites;
deadbeef7914b8c2017-04-21 03:23:33 -07001814 GetSupportedVideoSdesCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001815 if (!CreateMediaContentOffer(
1816 options,
1817 video_codecs,
1818 sdes_policy,
1819 GetCryptos(GetFirstVideoContentDescription(current_description)),
1820 crypto_suites,
1821 video_rtp_extensions,
1822 add_legacy_,
1823 current_streams,
1824 video.get())) {
1825 return false;
1826 }
1827
1828 video->set_bandwidth(options.video_bandwidth);
1829
1830 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1831 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001832
deadbeefc80741f2015-10-22 13:14:45 -07001833 if (!video->streams().empty()) {
1834 if (options.recv_video) {
1835 video->set_direction(MD_SENDRECV);
1836 } else {
1837 video->set_direction(MD_SENDONLY);
1838 }
1839 } else {
1840 if (options.recv_video) {
1841 video->set_direction(MD_RECVONLY);
1842 } else {
1843 video->set_direction(MD_INACTIVE);
1844 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001845 }
1846
deadbeef44f08192015-12-15 16:20:09 -08001847 desc->AddContent(content_name, NS_JINGLE_RTP, video.release());
deadbeef0ed85b22016-02-23 17:24:52 -08001848 if (!AddTransportOffer(content_name,
1849 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001850 current_description, desc)) {
1851 return false;
1852 }
1853
1854 return true;
1855}
1856
1857bool MediaSessionDescriptionFactory::AddDataContentForOffer(
1858 const MediaSessionOptions& options,
1859 const SessionDescription* current_description,
1860 DataCodecs* data_codecs,
1861 StreamParamsVec* current_streams,
1862 SessionDescription* desc) const {
1863 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1864
kwiberg31022942016-03-11 14:18:21 -08001865 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001866 bool is_sctp = (options.data_channel_type == DCT_SCTP);
1867
1868 FilterDataCodecs(data_codecs, is_sctp);
1869
deadbeef44f08192015-12-15 16:20:09 -08001870 const ContentInfo* current_data_content =
1871 GetFirstDataContent(current_description);
1872 std::string content_name =
1873 current_data_content ? current_data_content->name : CN_DATA;
1874
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001875 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001876 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1877 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001878 std::vector<std::string> crypto_suites;
1879 if (is_sctp) {
1880 // SDES doesn't make sense for SCTP, so we disable it, and we only
1881 // get SDES crypto suites for RTP-based data channels.
1882 sdes_policy = cricket::SEC_DISABLED;
1883 // Unlike SetMediaProtocol below, we need to set the protocol
1884 // before we call CreateMediaContentOffer. Otherwise,
1885 // CreateMediaContentOffer won't know this is SCTP and will
1886 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07001887 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
1888 // it's safe to do so. Older versions of webrtc would reject these
1889 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001890 data->set_protocol(
1891 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
1892 } else {
deadbeef7914b8c2017-04-21 03:23:33 -07001893 GetSupportedDataSdesCryptoSuiteNames(options.crypto_options,
1894 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001895 }
1896
1897 if (!CreateMediaContentOffer(
1898 options,
1899 *data_codecs,
1900 sdes_policy,
1901 GetCryptos(GetFirstDataContentDescription(current_description)),
1902 crypto_suites,
1903 RtpHeaderExtensions(),
1904 add_legacy_,
1905 current_streams,
1906 data.get())) {
1907 return false;
1908 }
1909
1910 if (is_sctp) {
deadbeef44f08192015-12-15 16:20:09 -08001911 desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001912 } else {
1913 data->set_bandwidth(options.data_bandwidth);
1914 SetMediaProtocol(secure_transport, data.get());
deadbeef44f08192015-12-15 16:20:09 -08001915 desc->AddContent(content_name, NS_JINGLE_RTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001916 }
deadbeef0ed85b22016-02-23 17:24:52 -08001917 if (!AddTransportOffer(content_name,
1918 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001919 current_description, desc)) {
1920 return false;
1921 }
1922 return true;
1923}
1924
1925bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
1926 const SessionDescription* offer,
1927 const MediaSessionOptions& options,
1928 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08001929 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001930 StreamParamsVec* current_streams,
1931 SessionDescription* answer) const {
1932 const ContentInfo* audio_content = GetFirstAudioContent(offer);
ossu075af922016-06-14 03:29:38 -07001933 const AudioContentDescription* offer_audio =
1934 static_cast<const AudioContentDescription*>(audio_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001935
deadbeefb7892532017-02-22 19:35:18 -08001936 std::unique_ptr<TransportDescription> audio_transport(
1937 CreateTransportAnswer(audio_content->name, offer,
1938 GetTransportOptions(options, audio_content->name),
1939 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001940 if (!audio_transport) {
1941 return false;
1942 }
1943
ossu075af922016-06-14 03:29:38 -07001944 // Pick codecs based on the requested communications direction in the offer.
1945 const bool wants_send =
1946 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1947 auto wants_rtd = RtpTransceiverDirection(wants_send, options.recv_audio);
1948 auto offer_rtd =
1949 RtpTransceiverDirection::FromMediaContentDirection(
1950 offer_audio->direction());
1951 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
1952 AudioCodecs audio_codecs = GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001953 if (!options.vad_enabled) {
1954 StripCNCodecs(&audio_codecs);
1955 }
1956
1957 bool bundle_enabled =
1958 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08001959 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001960 new AudioContentDescription());
1961 // Do not require or create SDES cryptos if DTLS is used.
1962 cricket::SecurePolicy sdes_policy =
1963 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
1964 if (!CreateMediaContentAnswer(
ossu075af922016-06-14 03:29:38 -07001965 offer_audio,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001966 options,
1967 audio_codecs,
1968 sdes_policy,
1969 GetCryptos(GetFirstAudioContentDescription(current_description)),
1970 audio_rtp_extensions_,
jbauch5869f502017-06-29 12:31:36 -07001971 enable_encrypted_rtp_header_extensions_,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001972 current_streams,
1973 add_legacy_,
1974 bundle_enabled,
1975 audio_answer.get())) {
1976 return false; // Fails the session setup.
1977 }
1978
deadbeefb7892532017-02-22 19:35:18 -08001979 bool secure = bundle_transport ? bundle_transport->description.secure()
1980 : audio_transport->secure();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001981 bool rejected = !options.has_audio() || audio_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08001982 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
1983 audio_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001984 if (!rejected) {
1985 AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer);
1986 } else {
1987 // RFC 3264
1988 // The answer MUST contain the same number of m-lines as the offer.
1989 LOG(LS_INFO) << "Audio is not supported in the answer.";
1990 }
1991
1992 answer->AddContent(audio_content->name, audio_content->type, rejected,
1993 audio_answer.release());
1994 return true;
1995}
1996
1997bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
1998 const SessionDescription* offer,
1999 const MediaSessionOptions& options,
2000 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002001 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002002 StreamParamsVec* current_streams,
2003 SessionDescription* answer) const {
2004 const ContentInfo* video_content = GetFirstVideoContent(offer);
deadbeefb7892532017-02-22 19:35:18 -08002005 std::unique_ptr<TransportDescription> video_transport(
2006 CreateTransportAnswer(video_content->name, offer,
2007 GetTransportOptions(options, video_content->name),
2008 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002009 if (!video_transport) {
2010 return false;
2011 }
2012
kwiberg31022942016-03-11 14:18:21 -08002013 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002014 new VideoContentDescription());
2015 // Do not require or create SDES cryptos if DTLS is used.
2016 cricket::SecurePolicy sdes_policy =
2017 video_transport->secure() ? cricket::SEC_DISABLED : secure();
2018 bool bundle_enabled =
2019 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
2020 if (!CreateMediaContentAnswer(
2021 static_cast<const VideoContentDescription*>(
2022 video_content->description),
2023 options,
2024 video_codecs_,
2025 sdes_policy,
2026 GetCryptos(GetFirstVideoContentDescription(current_description)),
2027 video_rtp_extensions_,
jbauch5869f502017-06-29 12:31:36 -07002028 enable_encrypted_rtp_header_extensions_,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002029 current_streams,
2030 add_legacy_,
2031 bundle_enabled,
2032 video_answer.get())) {
2033 return false;
2034 }
deadbeefb7892532017-02-22 19:35:18 -08002035 bool secure = bundle_transport ? bundle_transport->description.secure()
2036 : video_transport->secure();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00002037 bool rejected = !options.has_video() || video_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002038 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2039 video_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002040 if (!rejected) {
2041 if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
2042 answer)) {
2043 return false;
2044 }
2045 video_answer->set_bandwidth(options.video_bandwidth);
2046 } else {
2047 // RFC 3264
2048 // The answer MUST contain the same number of m-lines as the offer.
2049 LOG(LS_INFO) << "Video is not supported in the answer.";
2050 }
2051 answer->AddContent(video_content->name, video_content->type, rejected,
2052 video_answer.release());
2053 return true;
2054}
2055
2056bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
2057 const SessionDescription* offer,
2058 const MediaSessionOptions& options,
2059 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002060 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002061 StreamParamsVec* current_streams,
2062 SessionDescription* answer) const {
2063 const ContentInfo* data_content = GetFirstDataContent(offer);
deadbeefb7892532017-02-22 19:35:18 -08002064 std::unique_ptr<TransportDescription> data_transport(
2065 CreateTransportAnswer(data_content->name, offer,
2066 GetTransportOptions(options, data_content->name),
2067 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002068 if (!data_transport) {
2069 return false;
2070 }
2071 bool is_sctp = (options.data_channel_type == DCT_SCTP);
2072 std::vector<DataCodec> data_codecs(data_codecs_);
2073 FilterDataCodecs(&data_codecs, is_sctp);
2074
kwiberg31022942016-03-11 14:18:21 -08002075 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002076 new DataContentDescription());
2077 // Do not require or create SDES cryptos if DTLS is used.
2078 cricket::SecurePolicy sdes_policy =
2079 data_transport->secure() ? cricket::SEC_DISABLED : secure();
2080 bool bundle_enabled =
2081 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
2082 if (!CreateMediaContentAnswer(
2083 static_cast<const DataContentDescription*>(
2084 data_content->description),
2085 options,
2086 data_codecs_,
2087 sdes_policy,
2088 GetCryptos(GetFirstDataContentDescription(current_description)),
2089 RtpHeaderExtensions(),
jbauch5869f502017-06-29 12:31:36 -07002090 enable_encrypted_rtp_header_extensions_,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002091 current_streams,
2092 add_legacy_,
2093 bundle_enabled,
2094 data_answer.get())) {
2095 return false; // Fails the session setup.
2096 }
2097
zstein4b2e0822017-02-17 19:48:38 -08002098 // Respond with sctpmap if the offer uses sctpmap.
2099 const DataContentDescription* offer_data_description =
2100 static_cast<const DataContentDescription*>(data_content->description);
2101 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2102 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2103
deadbeefb7892532017-02-22 19:35:18 -08002104 bool secure = bundle_transport ? bundle_transport->description.secure()
2105 : data_transport->secure();
2106
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002107 bool rejected = !options.has_data() || data_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002108 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2109 data_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002110 if (!rejected) {
2111 data_answer->set_bandwidth(options.data_bandwidth);
2112 if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
2113 answer)) {
2114 return false;
2115 }
2116 } else {
2117 // RFC 3264
2118 // The answer MUST contain the same number of m-lines as the offer.
2119 LOG(LS_INFO) << "Data is not supported in the answer.";
2120 }
2121 answer->AddContent(data_content->name, data_content->type, rejected,
2122 data_answer.release());
2123 return true;
2124}
2125
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126bool IsMediaContent(const ContentInfo* content) {
2127 return (content &&
2128 (content->type == NS_JINGLE_RTP ||
2129 content->type == NS_JINGLE_DRAFT_SCTP));
2130}
2131
2132bool IsAudioContent(const ContentInfo* content) {
2133 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2134}
2135
2136bool IsVideoContent(const ContentInfo* content) {
2137 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2138}
2139
2140bool IsDataContent(const ContentInfo* content) {
2141 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2142}
2143
deadbeef0ed85b22016-02-23 17:24:52 -08002144const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2145 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002146 for (const ContentInfo& content : contents) {
2147 if (IsMediaContentOfType(&content, media_type)) {
2148 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 }
2150 }
deadbeef0ed85b22016-02-23 17:24:52 -08002151 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152}
2153
2154const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2155 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2156}
2157
2158const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2159 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2160}
2161
2162const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2163 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2164}
2165
2166static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2167 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002168 if (sdesc == nullptr) {
2169 return nullptr;
2170 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171
2172 return GetFirstMediaContent(sdesc->contents(), media_type);
2173}
2174
2175const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2176 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2177}
2178
2179const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2180 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2181}
2182
2183const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2184 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2185}
2186
2187const MediaContentDescription* GetFirstMediaContentDescription(
2188 const SessionDescription* sdesc, MediaType media_type) {
2189 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2190 const ContentDescription* description = content ? content->description : NULL;
2191 return static_cast<const MediaContentDescription*>(description);
2192}
2193
2194const AudioContentDescription* GetFirstAudioContentDescription(
2195 const SessionDescription* sdesc) {
2196 return static_cast<const AudioContentDescription*>(
2197 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2198}
2199
2200const VideoContentDescription* GetFirstVideoContentDescription(
2201 const SessionDescription* sdesc) {
2202 return static_cast<const VideoContentDescription*>(
2203 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2204}
2205
2206const DataContentDescription* GetFirstDataContentDescription(
2207 const SessionDescription* sdesc) {
2208 return static_cast<const DataContentDescription*>(
2209 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2210}
2211
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002212//
2213// Non-const versions of the above functions.
2214//
2215
2216ContentInfo* GetFirstMediaContent(ContentInfos& contents,
2217 MediaType media_type) {
2218 for (ContentInfo& content : contents) {
2219 if (IsMediaContentOfType(&content, media_type)) {
2220 return &content;
2221 }
2222 }
2223 return nullptr;
2224}
2225
2226ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
2227 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2228}
2229
2230ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
2231 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2232}
2233
2234ContentInfo* GetFirstDataContent(ContentInfos& contents) {
2235 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2236}
2237
2238static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2239 MediaType media_type) {
2240 if (sdesc == nullptr) {
2241 return nullptr;
2242 }
2243
2244 return GetFirstMediaContent(sdesc->contents(), media_type);
2245}
2246
2247ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2248 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2249}
2250
2251ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2252 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2253}
2254
2255ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2256 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2257}
2258
2259MediaContentDescription* GetFirstMediaContentDescription(
2260 SessionDescription* sdesc,
2261 MediaType media_type) {
2262 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2263 ContentDescription* description = content ? content->description : NULL;
2264 return static_cast<MediaContentDescription*>(description);
2265}
2266
2267AudioContentDescription* GetFirstAudioContentDescription(
2268 SessionDescription* sdesc) {
2269 return static_cast<AudioContentDescription*>(
2270 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2271}
2272
2273VideoContentDescription* GetFirstVideoContentDescription(
2274 SessionDescription* sdesc) {
2275 return static_cast<VideoContentDescription*>(
2276 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2277}
2278
2279DataContentDescription* GetFirstDataContentDescription(
2280 SessionDescription* sdesc) {
2281 return static_cast<DataContentDescription*>(
2282 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2283}
2284
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002285} // namespace cricket