blob: 5e380883896728d14d285f5ad00070e273f28d89 [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"
magjedf823ede2016-11-12 09:53:04 -080028#include "webrtc/common_video/h264/profile_level_id.h"
kjellandera96e2d72016-02-04 23:52:28 -080029#include "webrtc/media/base/cryptoparams.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
jbauchcb560652016-08-04 05:20:32 -070038void GetSupportedCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
39 std::vector<int>*),
40 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080041 std::vector<std::string>* names) {
42#ifdef HAVE_SRTP
43 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070044 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080045 for (const auto crypto : crypto_suites) {
46 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
47 }
48#endif
49}
terelius8c011e52016-04-26 05:28:11 -070050} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
52namespace cricket {
53
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054// RTP Profile names
55// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
56// RFC4585
57const char kMediaProtocolAvpf[] = "RTP/AVPF";
58// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000059const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
60
deadbeeff3938292015-07-15 12:20:53 -070061// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
62// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063const char kMediaProtocolSavpf[] = "RTP/SAVPF";
64
65const char kMediaProtocolRtpPrefix[] = "RTP/";
66
67const char kMediaProtocolSctp[] = "SCTP";
68const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000069const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000070const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071
ossu075af922016-06-14 03:29:38 -070072RtpTransceiverDirection RtpTransceiverDirection::FromMediaContentDirection(
73 MediaContentDirection md) {
74 const bool send = (md == MD_SENDRECV || md == MD_SENDONLY);
75 const bool recv = (md == MD_SENDRECV || md == MD_RECVONLY);
76 return RtpTransceiverDirection(send, recv);
77}
78
79MediaContentDirection RtpTransceiverDirection::ToMediaContentDirection() const {
80 if (send && recv) {
81 return MD_SENDRECV;
82 } else if (send) {
83 return MD_SENDONLY;
84 } else if (recv) {
85 return MD_RECVONLY;
86 }
87
88 return MD_INACTIVE;
89}
90
91RtpTransceiverDirection
92NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
93 RtpTransceiverDirection wants) {
94 return RtpTransceiverDirection(offer.recv && wants.send,
95 offer.send && wants.recv);
96}
97
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098static bool IsMediaContentOfType(const ContentInfo* content,
99 MediaType media_type) {
100 if (!IsMediaContent(content)) {
101 return false;
102 }
103
104 const MediaContentDescription* mdesc =
105 static_cast<const MediaContentDescription*>(content->description);
106 return mdesc && mdesc->type() == media_type;
107}
108
109static bool CreateCryptoParams(int tag, const std::string& cipher,
110 CryptoParams *out) {
jbauchcb560652016-08-04 05:20:32 -0700111 int key_len;
112 int salt_len;
113 if (!rtc::GetSrtpKeyAndSaltLengths(
114 rtc::SrtpCryptoSuiteFromName(cipher), &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return false;
116 }
jbauchcb560652016-08-04 05:20:32 -0700117
118 int master_key_len = key_len + salt_len;
119 std::string master_key;
120 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
121 return false;
122 }
123
kwiberg352444f2016-11-28 15:58:53 -0800124 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700125 std::string key = rtc::Base64::Encode(master_key);
126
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127 out->tag = tag;
128 out->cipher_suite = cipher;
129 out->key_params = kInline;
130 out->key_params += key;
131 return true;
132}
133
134#ifdef HAVE_SRTP
135static bool AddCryptoParams(const std::string& cipher_suite,
136 CryptoParamsVec *out) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000137 int size = static_cast<int>(out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
139 out->resize(size + 1);
140 return CreateCryptoParams(size, cipher_suite, &out->at(size));
141}
142
143void AddMediaCryptos(const CryptoParamsVec& cryptos,
144 MediaContentDescription* media) {
145 for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
146 crypto != cryptos.end(); ++crypto) {
147 media->AddCrypto(*crypto);
148 }
149}
150
151bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
152 MediaContentDescription* media) {
153 CryptoParamsVec cryptos;
154 for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
155 it != crypto_suites.end(); ++it) {
156 if (!AddCryptoParams(*it, &cryptos)) {
157 return false;
158 }
159 }
160 AddMediaCryptos(cryptos, media);
161 return true;
162}
163#endif
164
165const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
166 if (!media) {
167 return NULL;
168 }
169 return &media->cryptos();
170}
171
172bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
173 const CryptoParams& crypto,
174 CryptoParams* out) {
175 for (CryptoParamsVec::const_iterator it = cryptos.begin();
176 it != cryptos.end(); ++it) {
177 if (crypto.Matches(*it)) {
178 *out = *it;
179 return true;
180 }
181 }
182 return false;
183}
184
jbauchcb560652016-08-04 05:20:32 -0700185// For audio, HMAC 32 is prefered over HMAC 80 because of the low overhead.
186void GetSupportedAudioCryptoSuites(const rtc::CryptoOptions& crypto_options,
187 std::vector<int>* crypto_suites) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188#ifdef HAVE_SRTP
jbauchcb560652016-08-04 05:20:32 -0700189 if (crypto_options.enable_gcm_crypto_suites) {
190 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
191 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
192 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800193 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
194 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195#endif
196}
197
jbauchcb560652016-08-04 05:20:32 -0700198void GetSupportedAudioCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800199 std::vector<std::string>* crypto_suite_names) {
200 GetSupportedCryptoSuiteNames(GetSupportedAudioCryptoSuites,
jbauchcb560652016-08-04 05:20:32 -0700201 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202}
203
jbauchcb560652016-08-04 05:20:32 -0700204void GetSupportedVideoCryptoSuites(const rtc::CryptoOptions& crypto_options,
205 std::vector<int>* crypto_suites) {
206 GetDefaultSrtpCryptoSuites(crypto_options, crypto_suites);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207}
208
jbauchcb560652016-08-04 05:20:32 -0700209void GetSupportedVideoCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800210 std::vector<std::string>* crypto_suite_names) {
211 GetSupportedCryptoSuiteNames(GetSupportedVideoCryptoSuites,
jbauchcb560652016-08-04 05:20:32 -0700212 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800213}
214
jbauchcb560652016-08-04 05:20:32 -0700215void GetSupportedDataCryptoSuites(const rtc::CryptoOptions& crypto_options,
216 std::vector<int>* crypto_suites) {
217 GetDefaultSrtpCryptoSuites(crypto_options, crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800218}
219
jbauchcb560652016-08-04 05:20:32 -0700220void GetSupportedDataCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800221 std::vector<std::string>* crypto_suite_names) {
222 GetSupportedCryptoSuiteNames(GetSupportedDataCryptoSuites,
jbauchcb560652016-08-04 05:20:32 -0700223 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800224}
225
jbauchcb560652016-08-04 05:20:32 -0700226void GetDefaultSrtpCryptoSuites(const rtc::CryptoOptions& crypto_options,
227 std::vector<int>* crypto_suites) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228#ifdef HAVE_SRTP
jbauchcb560652016-08-04 05:20:32 -0700229 if (crypto_options.enable_gcm_crypto_suites) {
230 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
231 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
232 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800233 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234#endif
235}
236
jbauchcb560652016-08-04 05:20:32 -0700237void GetDefaultSrtpCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800238 std::vector<std::string>* crypto_suite_names) {
jbauchcb560652016-08-04 05:20:32 -0700239 GetSupportedCryptoSuiteNames(GetDefaultSrtpCryptoSuites,
240 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800241}
242
jbauchcb560652016-08-04 05:20:32 -0700243// Support any GCM cipher (if enabled through options). For video support only
244// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated unless bundle is enabled
245// because it is low overhead.
246// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000247static bool SelectCrypto(const MediaContentDescription* offer,
248 bool bundle,
jbauchcb560652016-08-04 05:20:32 -0700249 const rtc::CryptoOptions& crypto_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250 CryptoParams *crypto) {
251 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
252 const CryptoParamsVec& cryptos = offer->cryptos();
253
254 for (CryptoParamsVec::const_iterator i = cryptos.begin();
255 i != cryptos.end(); ++i) {
jbauchcb560652016-08-04 05:20:32 -0700256 if ((crypto_options.enable_gcm_crypto_suites &&
257 rtc::IsGcmCryptoSuiteName(i->cipher_suite)) ||
258 rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
Guo-wei Shieh456696a2015-09-30 21:48:54 -0700259 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
260 !bundle)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
262 }
263 }
264 return false;
265}
266
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000268// The generated values are added to |ssrcs|.
269// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000271 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200272 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000273 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200274 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000276 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000277 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
279 ssrcs->push_back(candidate);
280 }
281}
282
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283// Finds all StreamParams of all media types and attach them to stream_params.
284static void GetCurrentStreamParams(const SessionDescription* sdesc,
285 StreamParamsVec* stream_params) {
286 if (!sdesc)
287 return;
288
289 const ContentInfos& contents = sdesc->contents();
290 for (ContentInfos::const_iterator content = contents.begin();
291 content != contents.end(); ++content) {
292 if (!IsMediaContent(&*content)) {
293 continue;
294 }
295 const MediaContentDescription* media =
296 static_cast<const MediaContentDescription*>(
297 content->description);
298 const StreamParamsVec& streams = media->streams();
299 for (StreamParamsVec::const_iterator it = streams.begin();
300 it != streams.end(); ++it) {
301 stream_params->push_back(*it);
302 }
303 }
304}
305
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000306// Filters the data codecs for the data channel type.
307void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
308 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700309 const char* codec_name =
310 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000311 for (std::vector<DataCodec>::iterator iter = codecs->begin();
312 iter != codecs->end();) {
solenberg9fa49752016-10-08 13:02:44 -0700313 if (CodecNamesEq(iter->name, codec_name)) {
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000314 iter = codecs->erase(iter);
315 } else {
316 ++iter;
317 }
318 }
319}
320
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321template <typename IdStruct>
322class UsedIds {
323 public:
324 UsedIds(int min_allowed_id, int max_allowed_id)
325 : min_allowed_id_(min_allowed_id),
326 max_allowed_id_(max_allowed_id),
327 next_id_(max_allowed_id) {
328 }
329
330 // Loops through all Id in |ids| and changes its id if it is
331 // already in use by another IdStruct. Call this methods with all Id
332 // in a session description to make sure no duplicate ids exists.
333 // Note that typename Id must be a type of IdStruct.
334 template <typename Id>
335 void FindAndSetIdUsed(std::vector<Id>* ids) {
336 for (typename std::vector<Id>::iterator it = ids->begin();
337 it != ids->end(); ++it) {
338 FindAndSetIdUsed(&*it);
339 }
340 }
341
342 // Finds and sets an unused id if the |idstruct| id is already in use.
343 void FindAndSetIdUsed(IdStruct* idstruct) {
344 const int original_id = idstruct->id;
345 int new_id = idstruct->id;
346
347 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
348 // If the original id is not in range - this is an id that can't be
349 // dynamically changed.
350 return;
351 }
352
353 if (IsIdUsed(original_id)) {
354 new_id = FindUnusedId();
355 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
356 << " to " << new_id;
357 idstruct->id = new_id;
358 }
359 SetIdUsed(new_id);
360 }
361
362 private:
363 // Returns the first unused id in reverse order.
364 // This hopefully reduce the risk of more collisions. We want to change the
365 // default ids as little as possible.
366 int FindUnusedId() {
367 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
368 --next_id_;
369 }
nisseede5da42017-01-12 05:15:36 -0800370 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371 return next_id_;
372 }
373
374 bool IsIdUsed(int new_id) {
375 return id_set_.find(new_id) != id_set_.end();
376 }
377
378 void SetIdUsed(int new_id) {
379 id_set_.insert(new_id);
380 }
381
382 const int min_allowed_id_;
383 const int max_allowed_id_;
384 int next_id_;
385 std::set<int> id_set_;
386};
387
388// Helper class used for finding duplicate RTP payload types among audio, video
389// and data codecs. When bundle is used the payload types may not collide.
390class UsedPayloadTypes : public UsedIds<Codec> {
391 public:
392 UsedPayloadTypes()
393 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
394 }
395
396
397 private:
398 static const int kDynamicPayloadTypeMin = 96;
399 static const int kDynamicPayloadTypeMax = 127;
400};
401
402// Helper class used for finding duplicate RTP Header extension ids among
403// audio and video extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700404class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 public:
406 UsedRtpHeaderExtensionIds()
isheriff6f8d6862016-05-26 11:24:55 -0700407 : UsedIds<webrtc::RtpExtension>(kLocalIdMin, kLocalIdMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408
409 private:
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000410 // Min and Max local identifier for one-byte header extensions, per RFC5285.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 static const int kLocalIdMin = 1;
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000412 static const int kLocalIdMax = 14;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413};
414
415static bool IsSctp(const MediaContentDescription* desc) {
416 return ((desc->protocol() == kMediaProtocolSctp) ||
417 (desc->protocol() == kMediaProtocolDtlsSctp));
418}
419
420// Adds a StreamParams for each Stream in Streams with media type
421// media_type to content_description.
422// |current_params| - All currently known StreamParams of any media type.
423template <class C>
zhihuang8f65cdf2016-05-06 18:40:30 -0700424static bool AddStreamParams(MediaType media_type,
425 const MediaSessionOptions& options,
426 StreamParamsVec* current_streams,
427 MediaContentDescriptionImpl<C>* content_description,
428 const bool add_legacy_stream) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700429 // SCTP streams are not negotiated using SDP/ContentDescriptions.
430 if (IsSctp(content_description)) {
431 return true;
432 }
433
Noah Richards2e7a0982015-05-18 14:02:54 -0700434 const bool include_rtx_streams =
435 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436
zhihuang8f65cdf2016-05-06 18:40:30 -0700437 const MediaSessionOptions::Streams& streams = options.streams;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 if (streams.empty() && add_legacy_stream) {
439 // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200440 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700441 int num_ssrcs = include_rtx_streams ? 2 : 1;
442 GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
Noah Richards2e7a0982015-05-18 14:02:54 -0700443 if (include_rtx_streams) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
445 content_description->set_multistream(true);
446 } else {
447 content_description->AddLegacyStream(ssrcs[0]);
448 }
449 return true;
450 }
451
brandtr03d5fb12016-11-22 03:37:59 -0800452 const bool include_flexfec_stream =
453 ContainsFlexfecCodec(content_description->codecs());
454
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 MediaSessionOptions::Streams::const_iterator stream_it;
456 for (stream_it = streams.begin();
457 stream_it != streams.end(); ++stream_it) {
458 if (stream_it->type != media_type)
459 continue; // Wrong media type.
460
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000461 const StreamParams* param =
462 GetStreamByIds(*current_streams, "", stream_it->id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 // groupid is empty for StreamParams generated using
464 // MediaSessionDescriptionFactory.
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000465 if (!param) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000466 // This is a new stream.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200467 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700468 GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 StreamParams stream_param;
470 stream_param.id = stream_it->id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000471 // Add the generated ssrc.
472 for (size_t i = 0; i < ssrcs.size(); ++i) {
473 stream_param.ssrcs.push_back(ssrcs[i]);
474 }
475 if (stream_it->num_sim_layers > 1) {
476 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
477 stream_param.ssrc_groups.push_back(group);
478 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700479 // Generate extra ssrcs for include_rtx_streams case.
480 if (include_rtx_streams) {
481 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200482 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700483 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
484 &rtx_ssrcs);
485 for (size_t i = 0; i < ssrcs.size(); ++i) {
486 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
487 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 content_description->set_multistream(true);
489 }
brandtr03d5fb12016-11-22 03:37:59 -0800490 // Generate extra ssrc for include_flexfec_stream case.
491 if (include_flexfec_stream) {
492 // TODO(brandtr): Update when we support multistream protection.
493 if (ssrcs.size() == 1) {
494 std::vector<uint32_t> flexfec_ssrcs;
495 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
496 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
497 content_description->set_multistream(true);
498 } else if (!ssrcs.empty()) {
499 LOG(LS_WARNING)
500 << "Our FlexFEC implementation only supports protecting "
501 << "a single media streams. This session has multiple "
502 << "media streams however, so no FlexFEC SSRC will be generated.";
503 }
504 }
zhihuang8f65cdf2016-05-06 18:40:30 -0700505 stream_param.cname = options.rtcp_cname;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 stream_param.sync_label = stream_it->sync_label;
507 content_description->AddStream(stream_param);
508
509 // Store the new StreamParams in current_streams.
510 // This is necessary so that we can use the CNAME for other media types.
511 current_streams->push_back(stream_param);
512 } else {
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000513 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 }
515 }
516 return true;
517}
518
519// Updates the transport infos of the |sdesc| according to the given
520// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800521// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
522// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
524 SessionDescription* sdesc) {
525 // The bundle should not be empty.
526 if (!sdesc || !bundle_group.FirstContentName()) {
527 return false;
528 }
529
530 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700531 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 const TransportInfo* selected_transport_info =
533 sdesc->GetTransportInfoByName(selected_content_name);
534 if (!selected_transport_info) {
535 return false;
536 }
537
538 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700539 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700541 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800543 ConnectionRole selected_connection_role =
544 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 for (TransportInfos::iterator it =
546 sdesc->transport_infos().begin();
547 it != sdesc->transport_infos().end(); ++it) {
548 if (bundle_group.HasContentName(it->content_name) &&
549 it->content_name != selected_content_name) {
550 it->description.ice_ufrag = selected_ufrag;
551 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800552 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 }
554 }
555 return true;
556}
557
558// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
559// sets it to |cryptos|.
560static bool GetCryptosByName(const SessionDescription* sdesc,
561 const std::string& content_name,
562 CryptoParamsVec* cryptos) {
563 if (!sdesc || !cryptos) {
564 return false;
565 }
566
567 const ContentInfo* content = sdesc->GetContentByName(content_name);
568 if (!IsMediaContent(content) || !content->description) {
569 return false;
570 }
571
572 const MediaContentDescription* media_desc =
573 static_cast<const MediaContentDescription*>(content->description);
574 *cryptos = media_desc->cryptos();
575 return true;
576}
577
578// Predicate function used by the remove_if.
579// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
580static bool CryptoNotFound(const CryptoParams crypto,
581 const CryptoParamsVec* filter) {
582 if (filter == NULL) {
583 return true;
584 }
585 for (CryptoParamsVec::const_iterator it = filter->begin();
586 it != filter->end(); ++it) {
587 if (it->cipher_suite == crypto.cipher_suite) {
588 return false;
589 }
590 }
591 return true;
592}
593
594// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
595// which are not available in |filter|.
596static void PruneCryptos(const CryptoParamsVec& filter,
597 CryptoParamsVec* target_cryptos) {
598 if (!target_cryptos) {
599 return;
600 }
601 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
602 target_cryptos->end(),
603 bind2nd(ptr_fun(CryptoNotFound),
604 &filter)),
605 target_cryptos->end());
606}
607
deadbeefb5cb19b2015-11-23 16:39:12 -0800608static bool IsRtpProtocol(const std::string& protocol) {
609 return protocol.empty() ||
610 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
611}
612
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613static bool IsRtpContent(SessionDescription* sdesc,
614 const std::string& content_name) {
615 bool is_rtp = false;
616 ContentInfo* content = sdesc->GetContentByName(content_name);
617 if (IsMediaContent(content)) {
618 MediaContentDescription* media_desc =
619 static_cast<MediaContentDescription*>(content->description);
620 if (!media_desc) {
621 return false;
622 }
deadbeefb5cb19b2015-11-23 16:39:12 -0800623 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 }
625 return is_rtp;
626}
627
628// Updates the crypto parameters of the |sdesc| according to the given
629// |bundle_group|. The crypto parameters of all the contents within the
630// |bundle_group| should be updated to use the common subset of the
631// available cryptos.
632static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
633 SessionDescription* sdesc) {
634 // The bundle should not be empty.
635 if (!sdesc || !bundle_group.FirstContentName()) {
636 return false;
637 }
638
wu@webrtc.org78187522013-10-07 23:32:02 +0000639 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 // Get the common cryptos.
641 const ContentNames& content_names = bundle_group.content_names();
642 CryptoParamsVec common_cryptos;
643 for (ContentNames::const_iterator it = content_names.begin();
644 it != content_names.end(); ++it) {
645 if (!IsRtpContent(sdesc, *it)) {
646 continue;
647 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000648 // The common cryptos are needed if any of the content does not have DTLS
649 // enabled.
650 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
651 common_cryptos_needed = true;
652 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 if (it == content_names.begin()) {
654 // Initial the common_cryptos with the first content in the bundle group.
655 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
656 return false;
657 }
658 if (common_cryptos.empty()) {
659 // If there's no crypto params, we should just return.
660 return true;
661 }
662 } else {
663 CryptoParamsVec cryptos;
664 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
665 return false;
666 }
667 PruneCryptos(cryptos, &common_cryptos);
668 }
669 }
670
wu@webrtc.org78187522013-10-07 23:32:02 +0000671 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 return false;
673 }
674
675 // Update to use the common cryptos.
676 for (ContentNames::const_iterator it = content_names.begin();
677 it != content_names.end(); ++it) {
678 if (!IsRtpContent(sdesc, *it)) {
679 continue;
680 }
681 ContentInfo* content = sdesc->GetContentByName(*it);
682 if (IsMediaContent(content)) {
683 MediaContentDescription* media_desc =
684 static_cast<MediaContentDescription*>(content->description);
685 if (!media_desc) {
686 return false;
687 }
688 media_desc->set_cryptos(common_cryptos);
689 }
690 }
691 return true;
692}
693
694template <class C>
695static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800696 for (const auto& codec : codecs) {
697 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 return true;
699 }
700 }
701 return false;
702}
703
704template <class C>
705static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800706 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707}
708
brandtr03d5fb12016-11-22 03:37:59 -0800709template <class C>
710static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
711 for (const auto& codec : codecs) {
712 if (IsFlexfecCodec(codec)) {
713 return true;
714 }
715 }
716 return false;
717}
718
719template <class C>
720static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800721 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800722}
723
deadbeef0ed85b22016-02-23 17:24:52 -0800724static TransportOptions GetTransportOptions(const MediaSessionOptions& options,
725 const std::string& content_name) {
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700726 TransportOptions transport_options;
deadbeef0ed85b22016-02-23 17:24:52 -0800727 auto it = options.transport_options.find(content_name);
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700728 if (it != options.transport_options.end()) {
729 transport_options = it->second;
deadbeef0ed85b22016-02-23 17:24:52 -0800730 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700731 transport_options.enable_ice_renomination = options.enable_ice_renomination;
732 return transport_options;
deadbeef0ed85b22016-02-23 17:24:52 -0800733}
734
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735// Create a media content to be offered in a session-initiate,
736// according to the given options.rtcp_mux, options.is_muc,
737// options.streams, codecs, secure_transport, crypto, and streams. If we don't
738// currently have crypto (in current_cryptos) and it is enabled (in
739// secure_policy), crypto is created (according to crypto_suites). If
740// add_legacy_stream is true, and current_streams is empty, a legacy
741// stream is created. The created content is added to the offer.
742template <class C>
743static bool CreateMediaContentOffer(
744 const MediaSessionOptions& options,
745 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000746 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 const CryptoParamsVec* current_cryptos,
748 const std::vector<std::string>& crypto_suites,
749 const RtpHeaderExtensions& rtp_extensions,
750 bool add_legacy_stream,
751 StreamParamsVec* current_streams,
752 MediaContentDescriptionImpl<C>* offer) {
753 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755 offer->set_rtcp_mux(options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700756 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
757 offer->set_rtcp_reduced_size(true);
758 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 offer->set_multistream(options.is_muc);
760 offer->set_rtp_header_extensions(rtp_extensions);
761
zhihuang8f65cdf2016-05-06 18:40:30 -0700762 if (!AddStreamParams(offer->type(), options, current_streams, offer,
763 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 return false;
765 }
766
767#ifdef HAVE_SRTP
768 if (secure_policy != SEC_DISABLED) {
769 if (current_cryptos) {
770 AddMediaCryptos(*current_cryptos, offer);
771 }
772 if (offer->cryptos().empty()) {
773 if (!CreateMediaCryptos(crypto_suites, offer)) {
774 return false;
775 }
776 }
777 }
778#endif
779
deadbeef7af91dd2016-12-13 11:29:11 -0800780 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 return false;
782 }
783 return true;
784}
785
786template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000787static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800788 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000789 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800790 const int codec2_id) {
791 const C* codec1 = FindCodecById(codecs1, codec1_id);
792 const C* codec2 = FindCodecById(codecs2, codec2_id);
793 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000794}
795
796template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797static void NegotiateCodecs(const std::vector<C>& local_codecs,
798 const std::vector<C>& offered_codecs,
799 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800800 for (const C& ours : local_codecs) {
801 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700802 // Note that we intentionally only find one matching codec for each of our
803 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800804 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
805 C negotiated = ours;
806 negotiated.IntersectFeedbackParams(theirs);
807 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800808 const auto apt_it =
809 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800810 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800811 RTC_DCHECK(apt_it != theirs.params.end());
812 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 }
magjedf823ede2016-11-12 09:53:04 -0800814 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
815 webrtc::H264::GenerateProfileLevelIdForAnswer(
816 ours.params, theirs.params, &negotiated.params);
817 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800818 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700819 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800820 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 }
822 }
deadbeef67cf2c12016-04-13 10:07:16 -0700823 // RFC3264: Although the answerer MAY list the formats in their desired
824 // order of preference, it is RECOMMENDED that unless there is a
825 // specific reason, the answerer list formats in the same relative order
826 // they were present in the offer.
827 std::unordered_map<int, int> payload_type_preferences;
828 int preference = static_cast<int>(offered_codecs.size() + 1);
829 for (const C& codec : offered_codecs) {
830 payload_type_preferences[codec.id] = preference--;
831 }
832 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
833 [&payload_type_preferences](const C& a, const C& b) {
834 return payload_type_preferences[a.id] >
835 payload_type_preferences[b.id];
836 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837}
838
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800839// Finds a codec in |codecs2| that matches |codec_to_match|, which is
840// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
841// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800843static bool FindMatchingCodec(const std::vector<C>& codecs1,
844 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 const C& codec_to_match,
846 C* found_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800847 for (const C& potential_match : codecs2) {
848 if (potential_match.Matches(codec_to_match)) {
849 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800850 int apt_value_1 = 0;
851 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800852 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
853 &apt_value_1) ||
854 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
855 &apt_value_2)) {
856 LOG(LS_WARNING) << "RTX missing associated payload type.";
857 continue;
858 }
859 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
860 apt_value_2)) {
861 continue;
862 }
863 }
864 if (found_codec) {
865 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 }
867 return true;
868 }
869 }
870 return false;
871}
872
873// Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
874// already exist in |offered_codecs| and ensure the payload types don't
875// collide.
876template <class C>
877static void FindCodecsToOffer(
878 const std::vector<C>& reference_codecs,
879 std::vector<C>* offered_codecs,
880 UsedPayloadTypes* used_pltypes) {
881
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800883 for (const C& reference_codec : reference_codecs) {
884 if (!IsRtxCodec(reference_codec) &&
885 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
886 reference_codec, nullptr)) {
887 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888 used_pltypes->FindAndSetIdUsed(&codec);
889 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890 }
891 }
892
893 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800894 for (const C& reference_codec : reference_codecs) {
895 if (IsRtxCodec(reference_codec) &&
896 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
897 reference_codec, nullptr)) {
898 C rtx_codec = reference_codec;
899
900 std::string associated_pt_str;
901 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
902 &associated_pt_str)) {
903 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
904 << " is missing an associated payload type.";
905 continue;
906 }
907
908 int associated_pt;
909 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
910 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
911 << " of RTX codec " << rtx_codec.name
912 << " to an integer.";
913 continue;
914 }
915
916 // Find the associated reference codec for the reference RTX codec.
magjedb05fa242016-11-11 04:00:16 -0800917 const C* associated_codec =
918 FindCodecById(reference_codecs, associated_pt);
919 if (!associated_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800920 LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
921 << associated_pt << " for RTX codec " << rtx_codec.name
922 << ".";
923 continue;
924 }
925
926 // Find a codec in the offered list that matches the reference codec.
927 // Its payload type may be different than the reference codec.
928 C matching_codec;
929 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800930 *associated_codec, &matching_codec)) {
931 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800932 << " codec.";
933 continue;
934 }
935
936 rtx_codec.params[kCodecParamAssociatedPayloadType] =
937 rtc::ToString(matching_codec.id);
938 used_pltypes->FindAndSetIdUsed(&rtx_codec);
939 offered_codecs->push_back(rtx_codec);
940 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 }
942}
943
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700945 const webrtc::RtpExtension& ext_to_match,
946 webrtc::RtpExtension* found_extension) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
948 it != extensions.end(); ++it) {
949 // We assume that all URIs are given in a canonical format.
950 if (it->uri == ext_to_match.uri) {
951 if (found_extension != NULL) {
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000952 *found_extension = *it;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953 }
954 return true;
955 }
956 }
957 return false;
958}
959
deadbeefa5b273a2015-08-20 17:30:13 -0700960// Iterates through |offered_extensions|, adding each one to |all_extensions|
961// and |used_ids|, and resolving ID conflicts. If an offered extension has the
962// same URI as one in |all_extensions|, it will re-use the same ID and won't be
963// treated as a conflict.
964static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions,
965 RtpHeaderExtensions* all_extensions,
966 UsedRtpHeaderExtensionIds* used_ids) {
967 for (auto& extension : *offered_extensions) {
isheriff6f8d6862016-05-26 11:24:55 -0700968 webrtc::RtpExtension existing;
deadbeefa5b273a2015-08-20 17:30:13 -0700969 if (FindByUri(*all_extensions, extension, &existing)) {
970 extension.id = existing.id;
971 } else {
972 used_ids->FindAndSetIdUsed(&extension);
973 all_extensions->push_back(extension);
974 }
975 }
976}
977
978// Adds |reference_extensions| to |offered_extensions|, while updating
979// |all_extensions| and |used_ids|.
980static void FindRtpHdrExtsToOffer(
981 const RtpHeaderExtensions& reference_extensions,
982 RtpHeaderExtensions* offered_extensions,
983 RtpHeaderExtensions* all_extensions,
984 UsedRtpHeaderExtensionIds* used_ids) {
985 for (auto reference_extension : reference_extensions) {
986 if (!FindByUri(*offered_extensions, reference_extension, NULL)) {
isheriff6f8d6862016-05-26 11:24:55 -0700987 webrtc::RtpExtension existing;
deadbeefa5b273a2015-08-20 17:30:13 -0700988 if (FindByUri(*all_extensions, reference_extension, &existing)) {
989 offered_extensions->push_back(existing);
990 } else {
991 used_ids->FindAndSetIdUsed(&reference_extension);
992 all_extensions->push_back(reference_extension);
993 offered_extensions->push_back(reference_extension);
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000994 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000995 }
996 }
997}
998
999static void NegotiateRtpHeaderExtensions(
1000 const RtpHeaderExtensions& local_extensions,
1001 const RtpHeaderExtensions& offered_extensions,
1002 RtpHeaderExtensions* negotiated_extenstions) {
1003 RtpHeaderExtensions::const_iterator ours;
1004 for (ours = local_extensions.begin();
1005 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 11:24:55 -07001006 webrtc::RtpExtension theirs;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001007 if (FindByUri(offered_extensions, *ours, &theirs)) {
1008 // We respond with their RTP header extension id.
1009 negotiated_extenstions->push_back(theirs);
1010 }
1011 }
1012}
1013
1014static void StripCNCodecs(AudioCodecs* audio_codecs) {
1015 AudioCodecs::iterator iter = audio_codecs->begin();
1016 while (iter != audio_codecs->end()) {
nisse21e4e0b2017-02-20 05:01:01 -08001017 if (STR_CASE_CMP(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 iter = audio_codecs->erase(iter);
1019 } else {
1020 ++iter;
1021 }
1022 }
1023}
1024
1025// Create a media content to be answered in a session-accept,
1026// according to the given options.rtcp_mux, options.streams, codecs,
1027// crypto, and streams. If we don't currently have crypto (in
1028// current_cryptos) and it is enabled (in secure_policy), crypto is
1029// created (according to crypto_suites). If add_legacy_stream is
1030// true, and current_streams is empty, a legacy stream is created.
1031// The codecs, rtcp_mux, and crypto are all negotiated with the offer
1032// from the incoming session-initiate. If the negotiation fails, this
1033// method returns false. The created content is added to the offer.
1034template <class C>
1035static bool CreateMediaContentAnswer(
1036 const MediaContentDescriptionImpl<C>* offer,
1037 const MediaSessionOptions& options,
1038 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001039 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 const CryptoParamsVec* current_cryptos,
1041 const RtpHeaderExtensions& local_rtp_extenstions,
1042 StreamParamsVec* current_streams,
1043 bool add_legacy_stream,
1044 bool bundle_enabled,
1045 MediaContentDescriptionImpl<C>* answer) {
1046 std::vector<C> negotiated_codecs;
1047 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1048 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 answer->set_protocol(offer->protocol());
1050 RtpHeaderExtensions negotiated_rtp_extensions;
1051 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1052 offer->rtp_header_extensions(),
1053 &negotiated_rtp_extensions);
1054 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1055
1056 answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001057 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1058 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1059 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060
1061 if (sdes_policy != SEC_DISABLED) {
1062 CryptoParams crypto;
jbauchcb560652016-08-04 05:20:32 -07001063 if (SelectCrypto(offer, bundle_enabled, options.crypto_options, &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 if (current_cryptos) {
1065 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1066 }
1067 answer->AddCrypto(crypto);
1068 }
1069 }
1070
deadbeef7af91dd2016-12-13 11:29:11 -08001071 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 return false;
1073 }
1074
zhihuang8f65cdf2016-05-06 18:40:30 -07001075 if (!AddStreamParams(answer->type(), options, current_streams, answer,
1076 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077 return false; // Something went seriously wrong.
1078 }
1079
1080 // Make sure the answer media content direction is per default set as
1081 // described in RFC3264 section 6.1.
ossu075af922016-06-14 03:29:38 -07001082 const bool is_data = !IsRtpProtocol(answer->protocol());
1083 const bool has_send_streams = !answer->streams().empty();
1084 const bool wants_send = has_send_streams || is_data;
1085 const bool recv_audio =
1086 answer->type() == cricket::MEDIA_TYPE_AUDIO && options.recv_audio;
1087 const bool recv_video =
1088 answer->type() == cricket::MEDIA_TYPE_VIDEO && options.recv_video;
1089 const bool recv_data =
1090 answer->type() == cricket::MEDIA_TYPE_DATA;
1091 const bool wants_receive = recv_audio || recv_video || recv_data;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092
ossu075af922016-06-14 03:29:38 -07001093 auto offer_rtd =
1094 RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
1095 auto wants_rtd = RtpTransceiverDirection(wants_send, wants_receive);
1096 answer->set_direction(NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd)
1097 .ToMediaContentDirection());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 return true;
1099}
1100
zhihuangcf5b37c2016-05-05 11:44:35 -07001101static bool IsDtlsRtp(const std::string& protocol) {
1102 // Most-likely values first.
1103 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
1104 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
1105}
1106
1107static bool IsPlainRtp(const std::string& protocol) {
1108 // Most-likely values first.
1109 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
1110 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
1111}
1112
1113static bool IsDtlsSctp(const std::string& protocol) {
1114 return protocol == "DTLS/SCTP";
1115}
1116
1117static bool IsPlainSctp(const std::string& protocol) {
1118 return protocol == "SCTP";
1119}
1120
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001121static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001122 const std::string& protocol,
1123 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001124 // Since not all applications serialize and deserialize the media protocol,
1125 // we will have to accept |protocol| to be empty.
1126 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 return true;
1128 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001129
zhihuangcf5b37c2016-05-05 11:44:35 -07001130 if (type == MEDIA_TYPE_DATA) {
1131 // Check for SCTP, but also for RTP for RTP-based data channels.
1132 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1133 if (secure_transport) {
1134 // Most likely scenarios first.
1135 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1136 IsPlainRtp(protocol);
1137 } else {
1138 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1139 }
1140 }
1141
1142 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1143 // JSEP specifies.
1144 if (secure_transport) {
1145 // Most likely scenarios first.
1146 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1147 } else {
1148 return IsPlainRtp(protocol);
1149 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150}
1151
1152static void SetMediaProtocol(bool secure_transport,
1153 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001154 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001155 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001156 else if (secure_transport)
1157 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 else
1159 desc->set_protocol(kMediaProtocolAvpf);
1160}
1161
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001162// Gets the TransportInfo of the given |content_name| from the
1163// |current_description|. If doesn't exist, returns a new one.
1164static const TransportDescription* GetTransportDescription(
1165 const std::string& content_name,
1166 const SessionDescription* current_description) {
1167 const TransportDescription* desc = NULL;
1168 if (current_description) {
1169 const TransportInfo* info =
1170 current_description->GetTransportInfoByName(content_name);
1171 if (info) {
1172 desc = &info->description;
1173 }
1174 }
1175 return desc;
1176}
1177
1178// Gets the current DTLS state from the transport description.
1179static bool IsDtlsActive(
1180 const std::string& content_name,
1181 const SessionDescription* current_description) {
1182 if (!current_description)
1183 return false;
1184
1185 const ContentInfo* content =
1186 current_description->GetContentByName(content_name);
1187 if (!content)
1188 return false;
1189
1190 const TransportDescription* current_tdesc =
1191 GetTransportDescription(content_name, current_description);
1192 if (!current_tdesc)
1193 return false;
1194
1195 return current_tdesc->secure();
1196}
1197
ossu075af922016-06-14 03:29:38 -07001198std::string MediaContentDirectionToString(MediaContentDirection direction) {
1199 std::string dir_str;
1200 switch (direction) {
1201 case MD_INACTIVE:
1202 dir_str = "inactive";
1203 break;
1204 case MD_SENDONLY:
1205 dir_str = "sendonly";
1206 break;
1207 case MD_RECVONLY:
1208 dir_str = "recvonly";
1209 break;
1210 case MD_SENDRECV:
1211 dir_str = "sendrecv";
1212 break;
1213 default:
nissec80e7412017-01-11 05:56:46 -08001214 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07001215 break;
1216 }
1217
1218 return dir_str;
1219}
1220
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001221void MediaSessionOptions::AddSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 const std::string& id,
1223 const std::string& sync_label) {
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001224 AddSendStreamInternal(type, id, sync_label, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001225}
1226
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001227void MediaSessionOptions::AddSendVideoStream(
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001228 const std::string& id,
1229 const std::string& sync_label,
1230 int num_sim_layers) {
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001231 AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001232}
1233
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001234void MediaSessionOptions::AddSendStreamInternal(
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001235 MediaType type,
1236 const std::string& id,
1237 const std::string& sync_label,
1238 int num_sim_layers) {
1239 streams.push_back(Stream(type, id, sync_label, num_sim_layers));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 // If we haven't already set the data_channel_type, and we add a
1242 // stream, we assume it's an RTP data stream.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001243 if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 data_channel_type = DCT_RTP;
1245}
1246
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001247void MediaSessionOptions::RemoveSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 const std::string& id) {
1249 Streams::iterator stream_it = streams.begin();
1250 for (; stream_it != streams.end(); ++stream_it) {
1251 if (stream_it->type == type && stream_it->id == id) {
1252 streams.erase(stream_it);
1253 return;
1254 }
1255 }
nissec80e7412017-01-11 05:56:46 -08001256 RTC_NOTREACHED();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257}
1258
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001259bool MediaSessionOptions::HasSendMediaStream(MediaType type) const {
1260 Streams::const_iterator stream_it = streams.begin();
1261 for (; stream_it != streams.end(); ++stream_it) {
1262 if (stream_it->type == type) {
1263 return true;
1264 }
1265 }
1266 return false;
1267}
1268
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1270 const TransportDescriptionFactory* transport_desc_factory)
1271 : secure_(SEC_DISABLED),
1272 add_legacy_(true),
1273 transport_desc_factory_(transport_desc_factory) {
1274}
1275
1276MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1277 ChannelManager* channel_manager,
1278 const TransportDescriptionFactory* transport_desc_factory)
1279 : secure_(SEC_DISABLED),
1280 add_legacy_(true),
1281 transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001282 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1283 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
1284 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001286 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1288 channel_manager->GetSupportedDataCodecs(&data_codecs_);
ossudedfd282016-06-14 07:12:39 -07001289 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
1290 &audio_sendrecv_codecs_);
ossu075af922016-06-14 03:29:38 -07001291}
1292
ossudedfd282016-06-14 07:12:39 -07001293const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1294 const {
ossu075af922016-06-14 03:29:38 -07001295 return audio_sendrecv_codecs_;
1296}
1297
1298const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1299 return audio_send_codecs_;
1300}
1301
1302const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1303 return audio_recv_codecs_;
1304}
1305
1306void MediaSessionDescriptionFactory::set_audio_codecs(
1307 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1308 audio_send_codecs_ = send_codecs;
1309 audio_recv_codecs_ = recv_codecs;
1310 audio_sendrecv_codecs_.clear();
1311 // Use NegotiateCodecs to merge our codec lists, since the operation is
1312 // essentially the same. Put send_codecs as the offered_codecs, which is the
1313 // order we'd like to follow. The reasoning is that encoding is usually more
1314 // expensive than decoding, and prioritizing a codec in the send list probably
1315 // means it's a codec we can handle efficiently.
1316 NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317}
1318
1319SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
1320 const MediaSessionOptions& options,
1321 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001322 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323
1324 StreamParamsVec current_streams;
1325 GetCurrentStreamParams(current_description, &current_streams);
1326
ossu075af922016-06-14 03:29:38 -07001327 const bool wants_send =
1328 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1329 const AudioCodecs& supported_audio_codecs =
1330 GetAudioCodecsForOffer({wants_send, options.recv_audio});
1331
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332 AudioCodecs audio_codecs;
1333 VideoCodecs video_codecs;
1334 DataCodecs data_codecs;
ossu075af922016-06-14 03:29:38 -07001335 GetCodecsToOffer(current_description, supported_audio_codecs,
1336 video_codecs_, data_codecs_,
1337 &audio_codecs, &video_codecs, &data_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338
1339 if (!options.vad_enabled) {
1340 // If application doesn't want CN codecs in offer.
1341 StripCNCodecs(&audio_codecs);
1342 }
1343
1344 RtpHeaderExtensions audio_rtp_extensions;
1345 RtpHeaderExtensions video_rtp_extensions;
1346 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1347 &video_rtp_extensions);
1348
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001349 bool audio_added = false;
1350 bool video_added = false;
1351 bool data_added = false;
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001352
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001353 // Iterate through the contents of |current_description| to maintain the order
1354 // of the m-lines in the new offer.
1355 if (current_description) {
1356 ContentInfos::const_iterator it = current_description->contents().begin();
1357 for (; it != current_description->contents().end(); ++it) {
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001358 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001359 if (!AddAudioContentForOffer(options, current_description,
1360 audio_rtp_extensions, audio_codecs,
1361 &current_streams, offer.get())) {
1362 return NULL;
1363 }
1364 audio_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001365 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001366 if (!AddVideoContentForOffer(options, current_description,
1367 video_rtp_extensions, video_codecs,
1368 &current_streams, offer.get())) {
1369 return NULL;
1370 }
1371 video_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001372 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) {
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001373 MediaSessionOptions options_copy(options);
1374 if (IsSctp(static_cast<const MediaContentDescription*>(
1375 it->description))) {
1376 options_copy.data_channel_type = DCT_SCTP;
1377 }
1378 if (!AddDataContentForOffer(options_copy, current_description,
1379 &data_codecs, &current_streams,
1380 offer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001381 return NULL;
1382 }
1383 data_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001384 } else {
nissec80e7412017-01-11 05:56:46 -08001385 RTC_NOTREACHED();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001386 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001387 }
1388 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001389
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001390 // Append contents that are not in |current_description|.
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001391 if (!audio_added && options.has_audio() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001392 !AddAudioContentForOffer(options, current_description,
1393 audio_rtp_extensions, audio_codecs,
1394 &current_streams, offer.get())) {
1395 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001396 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001397 if (!video_added && options.has_video() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001398 !AddVideoContentForOffer(options, current_description,
1399 video_rtp_extensions, video_codecs,
1400 &current_streams, offer.get())) {
1401 return NULL;
1402 }
1403 if (!data_added && options.has_data() &&
1404 !AddDataContentForOffer(options, current_description, &data_codecs,
1405 &current_streams, offer.get())) {
1406 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001407 }
1408
1409 // Bundle the contents together, if we've been asked to do so, and update any
1410 // parameters that need to be tweaked for BUNDLE.
1411 if (options.bundle_enabled) {
1412 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
1413 for (ContentInfos::const_iterator content = offer->contents().begin();
1414 content != offer->contents().end(); ++content) {
1415 offer_bundle.AddContentName(content->name);
1416 }
1417 offer->AddGroup(offer_bundle);
1418 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1419 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
1420 return NULL;
1421 }
1422 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1423 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1424 return NULL;
1425 }
1426 }
1427
1428 return offer.release();
1429}
1430
1431SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
1432 const SessionDescription* offer, const MediaSessionOptions& options,
1433 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001434 if (!offer) {
1435 return nullptr;
1436 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001437 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001438 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1439 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001440 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001441
1442 StreamParamsVec current_streams;
1443 GetCurrentStreamParams(current_description, &current_streams);
1444
deadbeefb7892532017-02-22 19:35:18 -08001445 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1446 // group in the answer with the appropriate content names.
1447 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1448 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1449 // Transport info shared by the bundle group.
1450 std::unique_ptr<TransportInfo> bundle_transport;
1451
1452 ContentInfos::const_iterator it = offer->contents().begin();
1453 for (; it != offer->contents().end(); ++it) {
1454 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
1455 if (!AddAudioContentForAnswer(offer, options, current_description,
1456 bundle_transport.get(), &current_streams,
1457 answer.get())) {
1458 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001459 }
deadbeefb7892532017-02-22 19:35:18 -08001460 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
1461 if (!AddVideoContentForAnswer(offer, options, current_description,
1462 bundle_transport.get(), &current_streams,
1463 answer.get())) {
1464 return NULL;
1465 }
1466 } else {
1467 RTC_DCHECK(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA));
1468 if (!AddDataContentForAnswer(offer, options, current_description,
1469 bundle_transport.get(), &current_streams,
1470 answer.get())) {
1471 return NULL;
1472 }
1473 }
1474 // See if we can add the newly generated m= section to the BUNDLE group in
1475 // the answer.
1476 ContentInfo& added = answer->contents().back();
1477 if (!added.rejected && options.bundle_enabled && offer_bundle &&
1478 offer_bundle->HasContentName(added.name)) {
1479 answer_bundle.AddContentName(added.name);
1480 bundle_transport.reset(
1481 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001483 }
1484
deadbeefb7892532017-02-22 19:35:18 -08001485 // Only put BUNDLE group in answer if nonempty.
1486 if (answer_bundle.FirstContentName()) {
1487 answer->AddGroup(answer_bundle);
1488
1489 // Share the same ICE credentials and crypto params across all contents,
1490 // as BUNDLE requires.
1491 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1492 LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1493 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495
deadbeefb7892532017-02-22 19:35:18 -08001496 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1497 LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1498 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499 }
1500 }
1501
1502 return answer.release();
1503}
1504
ossu075af922016-06-14 03:29:38 -07001505const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1506 const RtpTransceiverDirection& direction) const {
1507 // If stream is inactive - generate list as if sendrecv.
1508 if (direction.send == direction.recv) {
1509 return audio_sendrecv_codecs_;
1510 } else if (direction.send) {
1511 return audio_send_codecs_;
1512 } else {
1513 return audio_recv_codecs_;
1514 }
1515}
1516
1517const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1518 const RtpTransceiverDirection& offer,
1519 const RtpTransceiverDirection& answer) const {
1520 // For inactive and sendrecv answers, generate lists as if we were to accept
1521 // the offer's direction. See RFC 3264 Section 6.1.
1522 if (answer.send == answer.recv) {
1523 if (offer.send == offer.recv) {
1524 return audio_sendrecv_codecs_;
1525 } else if (offer.send) {
1526 return audio_recv_codecs_;
1527 } else {
1528 return audio_send_codecs_;
1529 }
1530 } else if (answer.send) {
1531 return audio_send_codecs_;
1532 } else {
1533 return audio_recv_codecs_;
1534 }
1535}
1536
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537void MediaSessionDescriptionFactory::GetCodecsToOffer(
1538 const SessionDescription* current_description,
ossu075af922016-06-14 03:29:38 -07001539 const AudioCodecs& supported_audio_codecs,
1540 const VideoCodecs& supported_video_codecs,
1541 const DataCodecs& supported_data_codecs,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542 AudioCodecs* audio_codecs,
1543 VideoCodecs* video_codecs,
1544 DataCodecs* data_codecs) const {
1545 UsedPayloadTypes used_pltypes;
1546 audio_codecs->clear();
1547 video_codecs->clear();
1548 data_codecs->clear();
1549
1550
1551 // First - get all codecs from the current description if the media type
1552 // is used.
1553 // Add them to |used_pltypes| so the payloadtype is not reused if a new media
1554 // type is added.
1555 if (current_description) {
1556 const AudioContentDescription* audio =
1557 GetFirstAudioContentDescription(current_description);
1558 if (audio) {
1559 *audio_codecs = audio->codecs();
1560 used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
1561 }
1562 const VideoContentDescription* video =
1563 GetFirstVideoContentDescription(current_description);
1564 if (video) {
1565 *video_codecs = video->codecs();
1566 used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
1567 }
1568 const DataContentDescription* data =
1569 GetFirstDataContentDescription(current_description);
1570 if (data) {
1571 *data_codecs = data->codecs();
1572 used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
1573 }
1574 }
1575
1576 // Add our codecs that are not in |current_description|.
ossu075af922016-06-14 03:29:38 -07001577 FindCodecsToOffer<AudioCodec>(supported_audio_codecs, audio_codecs,
1578 &used_pltypes);
1579 FindCodecsToOffer<VideoCodec>(supported_video_codecs, video_codecs,
1580 &used_pltypes);
1581 FindCodecsToOffer<DataCodec>(supported_data_codecs, data_codecs,
1582 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001583}
1584
1585void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1586 const SessionDescription* current_description,
1587 RtpHeaderExtensions* audio_extensions,
1588 RtpHeaderExtensions* video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001589 // All header extensions allocated from the same range to avoid potential
1590 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001591 UsedRtpHeaderExtensionIds used_ids;
deadbeefa5b273a2015-08-20 17:30:13 -07001592 RtpHeaderExtensions all_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593 audio_extensions->clear();
1594 video_extensions->clear();
1595
1596 // First - get all extensions from the current description if the media type
1597 // is used.
1598 // Add them to |used_ids| so the local ids are not reused if a new media
1599 // type is added.
1600 if (current_description) {
1601 const AudioContentDescription* audio =
1602 GetFirstAudioContentDescription(current_description);
1603 if (audio) {
1604 *audio_extensions = audio->rtp_header_extensions();
deadbeefa5b273a2015-08-20 17:30:13 -07001605 FindAndSetRtpHdrExtUsed(audio_extensions, &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001606 }
1607 const VideoContentDescription* video =
1608 GetFirstVideoContentDescription(current_description);
1609 if (video) {
1610 *video_extensions = video->rtp_header_extensions();
deadbeefa5b273a2015-08-20 17:30:13 -07001611 FindAndSetRtpHdrExtUsed(video_extensions, &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612 }
1613 }
1614
1615 // Add our default RTP header extensions that are not in
1616 // |current_description|.
deadbeefa5b273a2015-08-20 17:30:13 -07001617 FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions,
1618 &all_extensions, &used_ids);
1619 FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions,
1620 &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621}
1622
1623bool MediaSessionDescriptionFactory::AddTransportOffer(
1624 const std::string& content_name,
1625 const TransportOptions& transport_options,
1626 const SessionDescription* current_desc,
1627 SessionDescription* offer_desc) const {
1628 if (!transport_desc_factory_)
1629 return false;
1630 const TransportDescription* current_tdesc =
1631 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001632 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1634 bool ret = (new_tdesc.get() != NULL &&
1635 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1636 if (!ret) {
1637 LOG(LS_ERROR)
1638 << "Failed to AddTransportOffer, content name=" << content_name;
1639 }
1640 return ret;
1641}
1642
1643TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1644 const std::string& content_name,
1645 const SessionDescription* offer_desc,
1646 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001647 const SessionDescription* current_desc,
1648 bool require_transport_attributes) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001649 if (!transport_desc_factory_)
1650 return NULL;
1651 const TransportDescription* offer_tdesc =
1652 GetTransportDescription(content_name, offer_desc);
1653 const TransportDescription* current_tdesc =
1654 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001655 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1656 require_transport_attributes,
1657 current_tdesc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001658}
1659
1660bool MediaSessionDescriptionFactory::AddTransportAnswer(
1661 const std::string& content_name,
1662 const TransportDescription& transport_desc,
1663 SessionDescription* answer_desc) const {
1664 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1665 transport_desc))) {
1666 LOG(LS_ERROR)
1667 << "Failed to AddTransportAnswer, content name=" << content_name;
1668 return false;
1669 }
1670 return true;
1671}
1672
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001673bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
1674 const MediaSessionOptions& options,
1675 const SessionDescription* current_description,
1676 const RtpHeaderExtensions& audio_rtp_extensions,
1677 const AudioCodecs& audio_codecs,
1678 StreamParamsVec* current_streams,
1679 SessionDescription* desc) const {
deadbeef44f08192015-12-15 16:20:09 -08001680 const ContentInfo* current_audio_content =
1681 GetFirstAudioContent(current_description);
1682 std::string content_name =
1683 current_audio_content ? current_audio_content->name : CN_AUDIO;
1684
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001685 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001686 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1687 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001688
kwiberg31022942016-03-11 14:18:21 -08001689 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001690 std::vector<std::string> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -07001691 GetSupportedAudioCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001692 if (!CreateMediaContentOffer(
1693 options,
1694 audio_codecs,
1695 sdes_policy,
1696 GetCryptos(GetFirstAudioContentDescription(current_description)),
1697 crypto_suites,
1698 audio_rtp_extensions,
1699 add_legacy_,
1700 current_streams,
1701 audio.get())) {
1702 return false;
1703 }
1704 audio->set_lang(lang_);
1705
1706 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1707 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001708
ossu075af922016-06-14 03:29:38 -07001709 auto offer_rtd =
1710 RtpTransceiverDirection(!audio->streams().empty(), options.recv_audio);
1711 audio->set_direction(offer_rtd.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001712
deadbeef44f08192015-12-15 16:20:09 -08001713 desc->AddContent(content_name, NS_JINGLE_RTP, audio.release());
deadbeef0ed85b22016-02-23 17:24:52 -08001714 if (!AddTransportOffer(content_name,
1715 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001716 current_description, desc)) {
1717 return false;
1718 }
1719
1720 return true;
1721}
1722
1723bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
1724 const MediaSessionOptions& options,
1725 const SessionDescription* current_description,
1726 const RtpHeaderExtensions& video_rtp_extensions,
1727 const VideoCodecs& video_codecs,
1728 StreamParamsVec* current_streams,
1729 SessionDescription* desc) const {
deadbeef44f08192015-12-15 16:20:09 -08001730 const ContentInfo* current_video_content =
1731 GetFirstVideoContent(current_description);
1732 std::string content_name =
1733 current_video_content ? current_video_content->name : CN_VIDEO;
1734
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001735 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001736 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1737 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001738
kwiberg31022942016-03-11 14:18:21 -08001739 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001740 std::vector<std::string> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -07001741 GetSupportedVideoCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001742 if (!CreateMediaContentOffer(
1743 options,
1744 video_codecs,
1745 sdes_policy,
1746 GetCryptos(GetFirstVideoContentDescription(current_description)),
1747 crypto_suites,
1748 video_rtp_extensions,
1749 add_legacy_,
1750 current_streams,
1751 video.get())) {
1752 return false;
1753 }
1754
1755 video->set_bandwidth(options.video_bandwidth);
1756
1757 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1758 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001759
deadbeefc80741f2015-10-22 13:14:45 -07001760 if (!video->streams().empty()) {
1761 if (options.recv_video) {
1762 video->set_direction(MD_SENDRECV);
1763 } else {
1764 video->set_direction(MD_SENDONLY);
1765 }
1766 } else {
1767 if (options.recv_video) {
1768 video->set_direction(MD_RECVONLY);
1769 } else {
1770 video->set_direction(MD_INACTIVE);
1771 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001772 }
1773
deadbeef44f08192015-12-15 16:20:09 -08001774 desc->AddContent(content_name, NS_JINGLE_RTP, video.release());
deadbeef0ed85b22016-02-23 17:24:52 -08001775 if (!AddTransportOffer(content_name,
1776 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001777 current_description, desc)) {
1778 return false;
1779 }
1780
1781 return true;
1782}
1783
1784bool MediaSessionDescriptionFactory::AddDataContentForOffer(
1785 const MediaSessionOptions& options,
1786 const SessionDescription* current_description,
1787 DataCodecs* data_codecs,
1788 StreamParamsVec* current_streams,
1789 SessionDescription* desc) const {
1790 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1791
kwiberg31022942016-03-11 14:18:21 -08001792 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001793 bool is_sctp = (options.data_channel_type == DCT_SCTP);
1794
1795 FilterDataCodecs(data_codecs, is_sctp);
1796
deadbeef44f08192015-12-15 16:20:09 -08001797 const ContentInfo* current_data_content =
1798 GetFirstDataContent(current_description);
1799 std::string content_name =
1800 current_data_content ? current_data_content->name : CN_DATA;
1801
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001802 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-15 16:20:09 -08001803 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1804 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001805 std::vector<std::string> crypto_suites;
1806 if (is_sctp) {
1807 // SDES doesn't make sense for SCTP, so we disable it, and we only
1808 // get SDES crypto suites for RTP-based data channels.
1809 sdes_policy = cricket::SEC_DISABLED;
1810 // Unlike SetMediaProtocol below, we need to set the protocol
1811 // before we call CreateMediaContentOffer. Otherwise,
1812 // CreateMediaContentOffer won't know this is SCTP and will
1813 // generate SSRCs rather than SIDs.
1814 data->set_protocol(
1815 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
1816 } else {
jbauchcb560652016-08-04 05:20:32 -07001817 GetSupportedDataCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001818 }
1819
1820 if (!CreateMediaContentOffer(
1821 options,
1822 *data_codecs,
1823 sdes_policy,
1824 GetCryptos(GetFirstDataContentDescription(current_description)),
1825 crypto_suites,
1826 RtpHeaderExtensions(),
1827 add_legacy_,
1828 current_streams,
1829 data.get())) {
1830 return false;
1831 }
1832
1833 if (is_sctp) {
deadbeef44f08192015-12-15 16:20:09 -08001834 desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001835 } else {
1836 data->set_bandwidth(options.data_bandwidth);
1837 SetMediaProtocol(secure_transport, data.get());
deadbeef44f08192015-12-15 16:20:09 -08001838 desc->AddContent(content_name, NS_JINGLE_RTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001839 }
deadbeef0ed85b22016-02-23 17:24:52 -08001840 if (!AddTransportOffer(content_name,
1841 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001842 current_description, desc)) {
1843 return false;
1844 }
1845 return true;
1846}
1847
1848bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
1849 const SessionDescription* offer,
1850 const MediaSessionOptions& options,
1851 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08001852 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001853 StreamParamsVec* current_streams,
1854 SessionDescription* answer) const {
1855 const ContentInfo* audio_content = GetFirstAudioContent(offer);
ossu075af922016-06-14 03:29:38 -07001856 const AudioContentDescription* offer_audio =
1857 static_cast<const AudioContentDescription*>(audio_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001858
deadbeefb7892532017-02-22 19:35:18 -08001859 std::unique_ptr<TransportDescription> audio_transport(
1860 CreateTransportAnswer(audio_content->name, offer,
1861 GetTransportOptions(options, audio_content->name),
1862 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001863 if (!audio_transport) {
1864 return false;
1865 }
1866
ossu075af922016-06-14 03:29:38 -07001867 // Pick codecs based on the requested communications direction in the offer.
1868 const bool wants_send =
1869 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1870 auto wants_rtd = RtpTransceiverDirection(wants_send, options.recv_audio);
1871 auto offer_rtd =
1872 RtpTransceiverDirection::FromMediaContentDirection(
1873 offer_audio->direction());
1874 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
1875 AudioCodecs audio_codecs = GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001876 if (!options.vad_enabled) {
1877 StripCNCodecs(&audio_codecs);
1878 }
1879
1880 bool bundle_enabled =
1881 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08001882 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001883 new AudioContentDescription());
1884 // Do not require or create SDES cryptos if DTLS is used.
1885 cricket::SecurePolicy sdes_policy =
1886 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
1887 if (!CreateMediaContentAnswer(
ossu075af922016-06-14 03:29:38 -07001888 offer_audio,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001889 options,
1890 audio_codecs,
1891 sdes_policy,
1892 GetCryptos(GetFirstAudioContentDescription(current_description)),
1893 audio_rtp_extensions_,
1894 current_streams,
1895 add_legacy_,
1896 bundle_enabled,
1897 audio_answer.get())) {
1898 return false; // Fails the session setup.
1899 }
1900
deadbeefb7892532017-02-22 19:35:18 -08001901 bool secure = bundle_transport ? bundle_transport->description.secure()
1902 : audio_transport->secure();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001903 bool rejected = !options.has_audio() || audio_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08001904 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
1905 audio_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001906 if (!rejected) {
1907 AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer);
1908 } else {
1909 // RFC 3264
1910 // The answer MUST contain the same number of m-lines as the offer.
1911 LOG(LS_INFO) << "Audio is not supported in the answer.";
1912 }
1913
1914 answer->AddContent(audio_content->name, audio_content->type, rejected,
1915 audio_answer.release());
1916 return true;
1917}
1918
1919bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
1920 const SessionDescription* offer,
1921 const MediaSessionOptions& options,
1922 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08001923 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001924 StreamParamsVec* current_streams,
1925 SessionDescription* answer) const {
1926 const ContentInfo* video_content = GetFirstVideoContent(offer);
deadbeefb7892532017-02-22 19:35:18 -08001927 std::unique_ptr<TransportDescription> video_transport(
1928 CreateTransportAnswer(video_content->name, offer,
1929 GetTransportOptions(options, video_content->name),
1930 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001931 if (!video_transport) {
1932 return false;
1933 }
1934
kwiberg31022942016-03-11 14:18:21 -08001935 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001936 new VideoContentDescription());
1937 // Do not require or create SDES cryptos if DTLS is used.
1938 cricket::SecurePolicy sdes_policy =
1939 video_transport->secure() ? cricket::SEC_DISABLED : secure();
1940 bool bundle_enabled =
1941 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
1942 if (!CreateMediaContentAnswer(
1943 static_cast<const VideoContentDescription*>(
1944 video_content->description),
1945 options,
1946 video_codecs_,
1947 sdes_policy,
1948 GetCryptos(GetFirstVideoContentDescription(current_description)),
1949 video_rtp_extensions_,
1950 current_streams,
1951 add_legacy_,
1952 bundle_enabled,
1953 video_answer.get())) {
1954 return false;
1955 }
deadbeefb7892532017-02-22 19:35:18 -08001956 bool secure = bundle_transport ? bundle_transport->description.secure()
1957 : video_transport->secure();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001958 bool rejected = !options.has_video() || video_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08001959 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
1960 video_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001961 if (!rejected) {
1962 if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
1963 answer)) {
1964 return false;
1965 }
1966 video_answer->set_bandwidth(options.video_bandwidth);
1967 } else {
1968 // RFC 3264
1969 // The answer MUST contain the same number of m-lines as the offer.
1970 LOG(LS_INFO) << "Video is not supported in the answer.";
1971 }
1972 answer->AddContent(video_content->name, video_content->type, rejected,
1973 video_answer.release());
1974 return true;
1975}
1976
1977bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
1978 const SessionDescription* offer,
1979 const MediaSessionOptions& options,
1980 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08001981 const TransportInfo* bundle_transport,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001982 StreamParamsVec* current_streams,
1983 SessionDescription* answer) const {
1984 const ContentInfo* data_content = GetFirstDataContent(offer);
deadbeefb7892532017-02-22 19:35:18 -08001985 std::unique_ptr<TransportDescription> data_transport(
1986 CreateTransportAnswer(data_content->name, offer,
1987 GetTransportOptions(options, data_content->name),
1988 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001989 if (!data_transport) {
1990 return false;
1991 }
1992 bool is_sctp = (options.data_channel_type == DCT_SCTP);
1993 std::vector<DataCodec> data_codecs(data_codecs_);
1994 FilterDataCodecs(&data_codecs, is_sctp);
1995
kwiberg31022942016-03-11 14:18:21 -08001996 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001997 new DataContentDescription());
1998 // Do not require or create SDES cryptos if DTLS is used.
1999 cricket::SecurePolicy sdes_policy =
2000 data_transport->secure() ? cricket::SEC_DISABLED : secure();
2001 bool bundle_enabled =
2002 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
2003 if (!CreateMediaContentAnswer(
2004 static_cast<const DataContentDescription*>(
2005 data_content->description),
2006 options,
2007 data_codecs_,
2008 sdes_policy,
2009 GetCryptos(GetFirstDataContentDescription(current_description)),
2010 RtpHeaderExtensions(),
2011 current_streams,
2012 add_legacy_,
2013 bundle_enabled,
2014 data_answer.get())) {
2015 return false; // Fails the session setup.
2016 }
2017
zstein4b2e0822017-02-17 19:48:38 -08002018 // Respond with sctpmap if the offer uses sctpmap.
2019 const DataContentDescription* offer_data_description =
2020 static_cast<const DataContentDescription*>(data_content->description);
2021 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2022 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2023
deadbeefb7892532017-02-22 19:35:18 -08002024 bool secure = bundle_transport ? bundle_transport->description.secure()
2025 : data_transport->secure();
2026
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002027 bool rejected = !options.has_data() || data_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002028 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2029 data_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002030 if (!rejected) {
2031 data_answer->set_bandwidth(options.data_bandwidth);
2032 if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
2033 answer)) {
2034 return false;
2035 }
2036 } else {
2037 // RFC 3264
2038 // The answer MUST contain the same number of m-lines as the offer.
2039 LOG(LS_INFO) << "Data is not supported in the answer.";
2040 }
2041 answer->AddContent(data_content->name, data_content->type, rejected,
2042 data_answer.release());
2043 return true;
2044}
2045
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002046bool IsMediaContent(const ContentInfo* content) {
2047 return (content &&
2048 (content->type == NS_JINGLE_RTP ||
2049 content->type == NS_JINGLE_DRAFT_SCTP));
2050}
2051
2052bool IsAudioContent(const ContentInfo* content) {
2053 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2054}
2055
2056bool IsVideoContent(const ContentInfo* content) {
2057 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2058}
2059
2060bool IsDataContent(const ContentInfo* content) {
2061 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2062}
2063
deadbeef0ed85b22016-02-23 17:24:52 -08002064const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2065 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002066 for (const ContentInfo& content : contents) {
2067 if (IsMediaContentOfType(&content, media_type)) {
2068 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 }
2070 }
deadbeef0ed85b22016-02-23 17:24:52 -08002071 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072}
2073
2074const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2075 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2076}
2077
2078const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2079 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2080}
2081
2082const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2083 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2084}
2085
2086static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2087 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002088 if (sdesc == nullptr) {
2089 return nullptr;
2090 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091
2092 return GetFirstMediaContent(sdesc->contents(), media_type);
2093}
2094
2095const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2096 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2097}
2098
2099const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2100 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2101}
2102
2103const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2104 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2105}
2106
2107const MediaContentDescription* GetFirstMediaContentDescription(
2108 const SessionDescription* sdesc, MediaType media_type) {
2109 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2110 const ContentDescription* description = content ? content->description : NULL;
2111 return static_cast<const MediaContentDescription*>(description);
2112}
2113
2114const AudioContentDescription* GetFirstAudioContentDescription(
2115 const SessionDescription* sdesc) {
2116 return static_cast<const AudioContentDescription*>(
2117 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2118}
2119
2120const VideoContentDescription* GetFirstVideoContentDescription(
2121 const SessionDescription* sdesc) {
2122 return static_cast<const VideoContentDescription*>(
2123 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2124}
2125
2126const DataContentDescription* GetFirstDataContentDescription(
2127 const SessionDescription* sdesc) {
2128 return static_cast<const DataContentDescription*>(
2129 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2130}
2131
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002132//
2133// Non-const versions of the above functions.
2134//
2135
2136ContentInfo* GetFirstMediaContent(ContentInfos& contents,
2137 MediaType media_type) {
2138 for (ContentInfo& content : contents) {
2139 if (IsMediaContentOfType(&content, media_type)) {
2140 return &content;
2141 }
2142 }
2143 return nullptr;
2144}
2145
2146ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
2147 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2148}
2149
2150ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
2151 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2152}
2153
2154ContentInfo* GetFirstDataContent(ContentInfos& contents) {
2155 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2156}
2157
2158static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2159 MediaType media_type) {
2160 if (sdesc == nullptr) {
2161 return nullptr;
2162 }
2163
2164 return GetFirstMediaContent(sdesc->contents(), media_type);
2165}
2166
2167ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2168 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2169}
2170
2171ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2172 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2173}
2174
2175ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2176 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2177}
2178
2179MediaContentDescription* GetFirstMediaContentDescription(
2180 SessionDescription* sdesc,
2181 MediaType media_type) {
2182 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2183 ContentDescription* description = content ? content->description : NULL;
2184 return static_cast<MediaContentDescription*>(description);
2185}
2186
2187AudioContentDescription* GetFirstAudioContentDescription(
2188 SessionDescription* sdesc) {
2189 return static_cast<AudioContentDescription*>(
2190 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2191}
2192
2193VideoContentDescription* GetFirstVideoContentDescription(
2194 SessionDescription* sdesc) {
2195 return static_cast<VideoContentDescription*>(
2196 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2197}
2198
2199DataContentDescription* GetFirstDataContentDescription(
2200 SessionDescription* sdesc) {
2201 return static_cast<DataContentDescription*>(
2202 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2203}
2204
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205} // namespace cricket