blob: ebba9acbcbf5adfddabb45eb31fb00575936a85b [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:361/*
kjellander65c7f672016-02-12 08:05:012 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:363 *
kjellander65c7f672016-02-12 08:05:014 * 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:369 */
10
kjellander@webrtc.org9b8df252016-02-12 05:47:5911#include "webrtc/pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:3612
deadbeef67cf2c12016-04-13 17:07:1613#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:3614#include <functional>
15#include <map>
kwiberg31022942016-03-11 22:18:2116#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:3617#include <set>
deadbeef67cf2c12016-04-13 17:07:1618#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:3619#include <utility>
20
jbauchcb560652016-08-04 12:20:3221#include "webrtc/base/base64.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:0822#include "webrtc/base/helpers.h"
23#include "webrtc/base/logging.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:0824#include "webrtc/base/stringutils.h"
kjellandera96e2d72016-02-05 07:52:2825#include "webrtc/media/base/cryptoparams.h"
kjellanderf4752772016-03-02 13:42:3026#include "webrtc/media/base/mediaconstants.h"
27#include "webrtc/p2p/base/p2pconstants.h"
kjellander@webrtc.org9b8df252016-02-12 05:47:5928#include "webrtc/pc/channelmanager.h"
29#include "webrtc/pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:3630
31namespace {
32const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-19 03:41:5333
jbauchcb560652016-08-04 12:20:3234void GetSupportedCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
35 std::vector<int>*),
36 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-19 03:41:5337 std::vector<std::string>* names) {
38#ifdef HAVE_SRTP
39 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 12:20:3240 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-19 03:41:5341 for (const auto crypto : crypto_suites) {
42 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
43 }
44#endif
45}
terelius8c011e52016-04-26 12:28:1146} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:3647
48namespace cricket {
49
henrike@webrtc.org28e20752013-07-10 00:45:3650// RTP Profile names
51// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
52// RFC4585
53const char kMediaProtocolAvpf[] = "RTP/AVPF";
54// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:5955const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
56
deadbeeff3938292015-07-15 19:20:5357// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
58// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:3659const char kMediaProtocolSavpf[] = "RTP/SAVPF";
60
61const char kMediaProtocolRtpPrefix[] = "RTP/";
62
63const char kMediaProtocolSctp[] = "SCTP";
64const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:4865const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:2166const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:3667
ossu075af922016-06-14 10:29:3868RtpTransceiverDirection RtpTransceiverDirection::FromMediaContentDirection(
69 MediaContentDirection md) {
70 const bool send = (md == MD_SENDRECV || md == MD_SENDONLY);
71 const bool recv = (md == MD_SENDRECV || md == MD_RECVONLY);
72 return RtpTransceiverDirection(send, recv);
73}
74
75MediaContentDirection RtpTransceiverDirection::ToMediaContentDirection() const {
76 if (send && recv) {
77 return MD_SENDRECV;
78 } else if (send) {
79 return MD_SENDONLY;
80 } else if (recv) {
81 return MD_RECVONLY;
82 }
83
84 return MD_INACTIVE;
85}
86
87RtpTransceiverDirection
88NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
89 RtpTransceiverDirection wants) {
90 return RtpTransceiverDirection(offer.recv && wants.send,
91 offer.send && wants.recv);
92}
93
henrike@webrtc.org28e20752013-07-10 00:45:3694static bool IsMediaContentOfType(const ContentInfo* content,
95 MediaType media_type) {
96 if (!IsMediaContent(content)) {
97 return false;
98 }
99
100 const MediaContentDescription* mdesc =
101 static_cast<const MediaContentDescription*>(content->description);
102 return mdesc && mdesc->type() == media_type;
103}
104
105static bool CreateCryptoParams(int tag, const std::string& cipher,
106 CryptoParams *out) {
jbauchcb560652016-08-04 12:20:32107 int key_len;
108 int salt_len;
109 if (!rtc::GetSrtpKeyAndSaltLengths(
110 rtc::SrtpCryptoSuiteFromName(cipher), &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36111 return false;
112 }
jbauchcb560652016-08-04 12:20:32113
114 int master_key_len = key_len + salt_len;
115 std::string master_key;
116 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
117 return false;
118 }
119
120 RTC_CHECK_EQ(static_cast<size_t>(master_key_len), master_key.size());
121 std::string key = rtc::Base64::Encode(master_key);
122
henrike@webrtc.org28e20752013-07-10 00:45:36123 out->tag = tag;
124 out->cipher_suite = cipher;
125 out->key_params = kInline;
126 out->key_params += key;
127 return true;
128}
129
130#ifdef HAVE_SRTP
131static bool AddCryptoParams(const std::string& cipher_suite,
132 CryptoParamsVec *out) {
henrike@webrtc.org28654cb2013-07-22 21:07:49133 int size = static_cast<int>(out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36134
135 out->resize(size + 1);
136 return CreateCryptoParams(size, cipher_suite, &out->at(size));
137}
138
139void AddMediaCryptos(const CryptoParamsVec& cryptos,
140 MediaContentDescription* media) {
141 for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
142 crypto != cryptos.end(); ++crypto) {
143 media->AddCrypto(*crypto);
144 }
145}
146
147bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
148 MediaContentDescription* media) {
149 CryptoParamsVec cryptos;
150 for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
151 it != crypto_suites.end(); ++it) {
152 if (!AddCryptoParams(*it, &cryptos)) {
153 return false;
154 }
155 }
156 AddMediaCryptos(cryptos, media);
157 return true;
158}
159#endif
160
161const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
162 if (!media) {
163 return NULL;
164 }
165 return &media->cryptos();
166}
167
168bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
169 const CryptoParams& crypto,
170 CryptoParams* out) {
171 for (CryptoParamsVec::const_iterator it = cryptos.begin();
172 it != cryptos.end(); ++it) {
173 if (crypto.Matches(*it)) {
174 *out = *it;
175 return true;
176 }
177 }
178 return false;
179}
180
jbauchcb560652016-08-04 12:20:32181// For audio, HMAC 32 is prefered over HMAC 80 because of the low overhead.
182void GetSupportedAudioCryptoSuites(const rtc::CryptoOptions& crypto_options,
183 std::vector<int>* crypto_suites) {
henrike@webrtc.org28e20752013-07-10 00:45:36184#ifdef HAVE_SRTP
jbauchcb560652016-08-04 12:20:32185 if (crypto_options.enable_gcm_crypto_suites) {
186 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
187 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
188 }
Guo-wei Shieh521ed7b2015-11-19 03:41:53189 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
190 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36191#endif
192}
193
jbauchcb560652016-08-04 12:20:32194void GetSupportedAudioCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-19 03:41:53195 std::vector<std::string>* crypto_suite_names) {
196 GetSupportedCryptoSuiteNames(GetSupportedAudioCryptoSuites,
jbauchcb560652016-08-04 12:20:32197 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36198}
199
jbauchcb560652016-08-04 12:20:32200void GetSupportedVideoCryptoSuites(const rtc::CryptoOptions& crypto_options,
201 std::vector<int>* crypto_suites) {
202 GetDefaultSrtpCryptoSuites(crypto_options, crypto_suites);
henrike@webrtc.org28e20752013-07-10 00:45:36203}
204
jbauchcb560652016-08-04 12:20:32205void GetSupportedVideoCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-19 03:41:53206 std::vector<std::string>* crypto_suite_names) {
207 GetSupportedCryptoSuiteNames(GetSupportedVideoCryptoSuites,
jbauchcb560652016-08-04 12:20:32208 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-19 03:41:53209}
210
jbauchcb560652016-08-04 12:20:32211void GetSupportedDataCryptoSuites(const rtc::CryptoOptions& crypto_options,
212 std::vector<int>* crypto_suites) {
213 GetDefaultSrtpCryptoSuites(crypto_options, crypto_suites);
Guo-wei Shieh521ed7b2015-11-19 03:41:53214}
215
jbauchcb560652016-08-04 12:20:32216void GetSupportedDataCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-19 03:41:53217 std::vector<std::string>* crypto_suite_names) {
218 GetSupportedCryptoSuiteNames(GetSupportedDataCryptoSuites,
jbauchcb560652016-08-04 12:20:32219 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-19 03:41:53220}
221
jbauchcb560652016-08-04 12:20:32222void GetDefaultSrtpCryptoSuites(const rtc::CryptoOptions& crypto_options,
223 std::vector<int>* crypto_suites) {
henrike@webrtc.org28e20752013-07-10 00:45:36224#ifdef HAVE_SRTP
jbauchcb560652016-08-04 12:20:32225 if (crypto_options.enable_gcm_crypto_suites) {
226 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
227 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
228 }
Guo-wei Shieh521ed7b2015-11-19 03:41:53229 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36230#endif
231}
232
jbauchcb560652016-08-04 12:20:32233void GetDefaultSrtpCryptoSuiteNames(const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-19 03:41:53234 std::vector<std::string>* crypto_suite_names) {
jbauchcb560652016-08-04 12:20:32235 GetSupportedCryptoSuiteNames(GetDefaultSrtpCryptoSuites,
236 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-19 03:41:53237}
238
jbauchcb560652016-08-04 12:20:32239// Support any GCM cipher (if enabled through options). For video support only
240// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated unless bundle is enabled
241// because it is low overhead.
242// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36243static bool SelectCrypto(const MediaContentDescription* offer,
244 bool bundle,
jbauchcb560652016-08-04 12:20:32245 const rtc::CryptoOptions& crypto_options,
henrike@webrtc.org28e20752013-07-10 00:45:36246 CryptoParams *crypto) {
247 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
248 const CryptoParamsVec& cryptos = offer->cryptos();
249
250 for (CryptoParamsVec::const_iterator i = cryptos.begin();
251 i != cryptos.end(); ++i) {
jbauchcb560652016-08-04 12:20:32252 if ((crypto_options.enable_gcm_crypto_suites &&
253 rtc::IsGcmCryptoSuiteName(i->cipher_suite)) ||
254 rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
Guo-wei Shieh456696a2015-10-01 04:48:54255 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
256 !bundle)) {
henrike@webrtc.org28e20752013-07-10 00:45:36257 return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
258 }
259 }
260 return false;
261}
262
henrike@webrtc.org28e20752013-07-10 00:45:36263// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12264// The generated values are added to |ssrcs|.
265// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36266static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12267 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 10:23:21268 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12269 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 10:23:21270 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36271 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52272 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41273 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36274 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
275 ssrcs->push_back(candidate);
276 }
277}
278
henrike@webrtc.org28e20752013-07-10 00:45:36279// Finds all StreamParams of all media types and attach them to stream_params.
280static void GetCurrentStreamParams(const SessionDescription* sdesc,
281 StreamParamsVec* stream_params) {
282 if (!sdesc)
283 return;
284
285 const ContentInfos& contents = sdesc->contents();
286 for (ContentInfos::const_iterator content = contents.begin();
287 content != contents.end(); ++content) {
288 if (!IsMediaContent(&*content)) {
289 continue;
290 }
291 const MediaContentDescription* media =
292 static_cast<const MediaContentDescription*>(
293 content->description);
294 const StreamParamsVec& streams = media->streams();
295 for (StreamParamsVec::const_iterator it = streams.begin();
296 it != streams.end(); ++it) {
297 stream_params->push_back(*it);
298 }
299 }
300}
301
jiayl@webrtc.org9c16c392014-05-01 18:30:30302// Filters the data codecs for the data channel type.
303void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
304 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 20:02:44305 const char* codec_name =
306 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
jiayl@webrtc.org9c16c392014-05-01 18:30:30307 for (std::vector<DataCodec>::iterator iter = codecs->begin();
308 iter != codecs->end();) {
solenberg9fa49752016-10-08 20:02:44309 if (CodecNamesEq(iter->name, codec_name)) {
jiayl@webrtc.org9c16c392014-05-01 18:30:30310 iter = codecs->erase(iter);
311 } else {
312 ++iter;
313 }
314 }
315}
316
henrike@webrtc.org28e20752013-07-10 00:45:36317template <typename IdStruct>
318class UsedIds {
319 public:
320 UsedIds(int min_allowed_id, int max_allowed_id)
321 : min_allowed_id_(min_allowed_id),
322 max_allowed_id_(max_allowed_id),
323 next_id_(max_allowed_id) {
324 }
325
326 // Loops through all Id in |ids| and changes its id if it is
327 // already in use by another IdStruct. Call this methods with all Id
328 // in a session description to make sure no duplicate ids exists.
329 // Note that typename Id must be a type of IdStruct.
330 template <typename Id>
331 void FindAndSetIdUsed(std::vector<Id>* ids) {
332 for (typename std::vector<Id>::iterator it = ids->begin();
333 it != ids->end(); ++it) {
334 FindAndSetIdUsed(&*it);
335 }
336 }
337
338 // Finds and sets an unused id if the |idstruct| id is already in use.
339 void FindAndSetIdUsed(IdStruct* idstruct) {
340 const int original_id = idstruct->id;
341 int new_id = idstruct->id;
342
343 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
344 // If the original id is not in range - this is an id that can't be
345 // dynamically changed.
346 return;
347 }
348
349 if (IsIdUsed(original_id)) {
350 new_id = FindUnusedId();
351 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
352 << " to " << new_id;
353 idstruct->id = new_id;
354 }
355 SetIdUsed(new_id);
356 }
357
358 private:
359 // Returns the first unused id in reverse order.
360 // This hopefully reduce the risk of more collisions. We want to change the
361 // default ids as little as possible.
362 int FindUnusedId() {
363 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
364 --next_id_;
365 }
366 ASSERT(next_id_ >= min_allowed_id_);
367 return next_id_;
368 }
369
370 bool IsIdUsed(int new_id) {
371 return id_set_.find(new_id) != id_set_.end();
372 }
373
374 void SetIdUsed(int new_id) {
375 id_set_.insert(new_id);
376 }
377
378 const int min_allowed_id_;
379 const int max_allowed_id_;
380 int next_id_;
381 std::set<int> id_set_;
382};
383
384// Helper class used for finding duplicate RTP payload types among audio, video
385// and data codecs. When bundle is used the payload types may not collide.
386class UsedPayloadTypes : public UsedIds<Codec> {
387 public:
388 UsedPayloadTypes()
389 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
390 }
391
392
393 private:
394 static const int kDynamicPayloadTypeMin = 96;
395 static const int kDynamicPayloadTypeMax = 127;
396};
397
398// Helper class used for finding duplicate RTP Header extension ids among
399// audio and video extensions.
isheriff6f8d6862016-05-26 18:24:55400class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36401 public:
402 UsedRtpHeaderExtensionIds()
isheriff6f8d6862016-05-26 18:24:55403 : UsedIds<webrtc::RtpExtension>(kLocalIdMin, kLocalIdMax) {}
henrike@webrtc.org28e20752013-07-10 00:45:36404
405 private:
henrike@webrtc.org79047f92014-03-06 23:46:59406 // Min and Max local identifier for one-byte header extensions, per RFC5285.
henrike@webrtc.org28e20752013-07-10 00:45:36407 static const int kLocalIdMin = 1;
henrike@webrtc.org79047f92014-03-06 23:46:59408 static const int kLocalIdMax = 14;
henrike@webrtc.org28e20752013-07-10 00:45:36409};
410
411static bool IsSctp(const MediaContentDescription* desc) {
412 return ((desc->protocol() == kMediaProtocolSctp) ||
413 (desc->protocol() == kMediaProtocolDtlsSctp));
414}
415
416// Adds a StreamParams for each Stream in Streams with media type
417// media_type to content_description.
418// |current_params| - All currently known StreamParams of any media type.
419template <class C>
zhihuang8f65cdf2016-05-07 01:40:30420static bool AddStreamParams(MediaType media_type,
421 const MediaSessionOptions& options,
422 StreamParamsVec* current_streams,
423 MediaContentDescriptionImpl<C>* content_description,
424 const bool add_legacy_stream) {
Taylor Brandstetter1d7a6372016-08-24 20:15:27425 // SCTP streams are not negotiated using SDP/ContentDescriptions.
426 if (IsSctp(content_description)) {
427 return true;
428 }
429
Noah Richards2e7a0982015-05-18 21:02:54430 const bool include_rtx_streams =
431 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36432
zhihuang8f65cdf2016-05-07 01:40:30433 const MediaSessionOptions::Streams& streams = options.streams;
henrike@webrtc.org28e20752013-07-10 00:45:36434 if (streams.empty() && add_legacy_stream) {
435 // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
Peter Boström0c4e06b2015-10-07 10:23:21436 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 20:15:27437 int num_ssrcs = include_rtx_streams ? 2 : 1;
438 GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
Noah Richards2e7a0982015-05-18 21:02:54439 if (include_rtx_streams) {
henrike@webrtc.org28e20752013-07-10 00:45:36440 content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
441 content_description->set_multistream(true);
442 } else {
443 content_description->AddLegacyStream(ssrcs[0]);
444 }
445 return true;
446 }
447
448 MediaSessionOptions::Streams::const_iterator stream_it;
449 for (stream_it = streams.begin();
450 stream_it != streams.end(); ++stream_it) {
451 if (stream_it->type != media_type)
452 continue; // Wrong media type.
453
tommi@webrtc.org586f2ed2015-01-22 23:00:41454 const StreamParams* param =
455 GetStreamByIds(*current_streams, "", stream_it->id);
henrike@webrtc.org28e20752013-07-10 00:45:36456 // groupid is empty for StreamParams generated using
457 // MediaSessionDescriptionFactory.
tommi@webrtc.org586f2ed2015-01-22 23:00:41458 if (!param) {
henrike@webrtc.org28e20752013-07-10 00:45:36459 // This is a new stream.
Peter Boström0c4e06b2015-10-07 10:23:21460 std::vector<uint32_t> ssrcs;
Taylor Brandstetter1d7a6372016-08-24 20:15:27461 GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36462 StreamParams stream_param;
463 stream_param.id = stream_it->id;
wu@webrtc.orgcecfd182013-10-30 05:18:12464 // Add the generated ssrc.
465 for (size_t i = 0; i < ssrcs.size(); ++i) {
466 stream_param.ssrcs.push_back(ssrcs[i]);
467 }
468 if (stream_it->num_sim_layers > 1) {
469 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
470 stream_param.ssrc_groups.push_back(group);
471 }
Noah Richards2e7a0982015-05-18 21:02:54472 // Generate extra ssrcs for include_rtx_streams case.
473 if (include_rtx_streams) {
474 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 10:23:21475 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 21:02:54476 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
477 &rtx_ssrcs);
478 for (size_t i = 0; i < ssrcs.size(); ++i) {
479 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
480 }
henrike@webrtc.org28e20752013-07-10 00:45:36481 content_description->set_multistream(true);
482 }
zhihuang8f65cdf2016-05-07 01:40:30483 stream_param.cname = options.rtcp_cname;
henrike@webrtc.org28e20752013-07-10 00:45:36484 stream_param.sync_label = stream_it->sync_label;
485 content_description->AddStream(stream_param);
486
487 // Store the new StreamParams in current_streams.
488 // This is necessary so that we can use the CNAME for other media types.
489 current_streams->push_back(stream_param);
490 } else {
tommi@webrtc.org586f2ed2015-01-22 23:00:41491 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36492 }
493 }
494 return true;
495}
496
497// Updates the transport infos of the |sdesc| according to the given
498// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d3652016-01-08 23:35:57499// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
500// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36501static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
502 SessionDescription* sdesc) {
503 // The bundle should not be empty.
504 if (!sdesc || !bundle_group.FirstContentName()) {
505 return false;
506 }
507
508 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 09:46:32509 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36510 const TransportInfo* selected_transport_info =
511 sdesc->GetTransportInfoByName(selected_content_name);
512 if (!selected_transport_info) {
513 return false;
514 }
515
516 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 09:46:32517 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36518 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 09:46:32519 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36520 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d3652016-01-08 23:35:57521 ConnectionRole selected_connection_role =
522 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36523 for (TransportInfos::iterator it =
524 sdesc->transport_infos().begin();
525 it != sdesc->transport_infos().end(); ++it) {
526 if (bundle_group.HasContentName(it->content_name) &&
527 it->content_name != selected_content_name) {
528 it->description.ice_ufrag = selected_ufrag;
529 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d3652016-01-08 23:35:57530 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36531 }
532 }
533 return true;
534}
535
536// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
537// sets it to |cryptos|.
538static bool GetCryptosByName(const SessionDescription* sdesc,
539 const std::string& content_name,
540 CryptoParamsVec* cryptos) {
541 if (!sdesc || !cryptos) {
542 return false;
543 }
544
545 const ContentInfo* content = sdesc->GetContentByName(content_name);
546 if (!IsMediaContent(content) || !content->description) {
547 return false;
548 }
549
550 const MediaContentDescription* media_desc =
551 static_cast<const MediaContentDescription*>(content->description);
552 *cryptos = media_desc->cryptos();
553 return true;
554}
555
556// Predicate function used by the remove_if.
557// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
558static bool CryptoNotFound(const CryptoParams crypto,
559 const CryptoParamsVec* filter) {
560 if (filter == NULL) {
561 return true;
562 }
563 for (CryptoParamsVec::const_iterator it = filter->begin();
564 it != filter->end(); ++it) {
565 if (it->cipher_suite == crypto.cipher_suite) {
566 return false;
567 }
568 }
569 return true;
570}
571
572// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
573// which are not available in |filter|.
574static void PruneCryptos(const CryptoParamsVec& filter,
575 CryptoParamsVec* target_cryptos) {
576 if (!target_cryptos) {
577 return;
578 }
579 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
580 target_cryptos->end(),
581 bind2nd(ptr_fun(CryptoNotFound),
582 &filter)),
583 target_cryptos->end());
584}
585
deadbeefb5cb19b2015-11-24 00:39:12586static bool IsRtpProtocol(const std::string& protocol) {
587 return protocol.empty() ||
588 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
589}
590
henrike@webrtc.org28e20752013-07-10 00:45:36591static bool IsRtpContent(SessionDescription* sdesc,
592 const std::string& content_name) {
593 bool is_rtp = false;
594 ContentInfo* content = sdesc->GetContentByName(content_name);
595 if (IsMediaContent(content)) {
596 MediaContentDescription* media_desc =
597 static_cast<MediaContentDescription*>(content->description);
598 if (!media_desc) {
599 return false;
600 }
deadbeefb5cb19b2015-11-24 00:39:12601 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36602 }
603 return is_rtp;
604}
605
606// Updates the crypto parameters of the |sdesc| according to the given
607// |bundle_group|. The crypto parameters of all the contents within the
608// |bundle_group| should be updated to use the common subset of the
609// available cryptos.
610static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
611 SessionDescription* sdesc) {
612 // The bundle should not be empty.
613 if (!sdesc || !bundle_group.FirstContentName()) {
614 return false;
615 }
616
wu@webrtc.org78187522013-10-07 23:32:02617 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36618 // Get the common cryptos.
619 const ContentNames& content_names = bundle_group.content_names();
620 CryptoParamsVec common_cryptos;
621 for (ContentNames::const_iterator it = content_names.begin();
622 it != content_names.end(); ++it) {
623 if (!IsRtpContent(sdesc, *it)) {
624 continue;
625 }
wu@webrtc.org78187522013-10-07 23:32:02626 // The common cryptos are needed if any of the content does not have DTLS
627 // enabled.
628 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
629 common_cryptos_needed = true;
630 }
henrike@webrtc.org28e20752013-07-10 00:45:36631 if (it == content_names.begin()) {
632 // Initial the common_cryptos with the first content in the bundle group.
633 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
634 return false;
635 }
636 if (common_cryptos.empty()) {
637 // If there's no crypto params, we should just return.
638 return true;
639 }
640 } else {
641 CryptoParamsVec cryptos;
642 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
643 return false;
644 }
645 PruneCryptos(cryptos, &common_cryptos);
646 }
647 }
648
wu@webrtc.org78187522013-10-07 23:32:02649 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36650 return false;
651 }
652
653 // Update to use the common cryptos.
654 for (ContentNames::const_iterator it = content_names.begin();
655 it != content_names.end(); ++it) {
656 if (!IsRtpContent(sdesc, *it)) {
657 continue;
658 }
659 ContentInfo* content = sdesc->GetContentByName(*it);
660 if (IsMediaContent(content)) {
661 MediaContentDescription* media_desc =
662 static_cast<MediaContentDescription*>(content->description);
663 if (!media_desc) {
664 return false;
665 }
666 media_desc->set_cryptos(common_cryptos);
667 }
668 }
669 return true;
670}
671
672template <class C>
673static bool ContainsRtxCodec(const std::vector<C>& codecs) {
674 typename std::vector<C>::const_iterator it;
675 for (it = codecs.begin(); it != codecs.end(); ++it) {
676 if (IsRtxCodec(*it)) {
677 return true;
678 }
679 }
680 return false;
681}
682
683template <class C>
684static bool IsRtxCodec(const C& codec) {
685 return stricmp(codec.name.c_str(), kRtxCodecName) == 0;
686}
687
deadbeef0ed85b22016-02-24 01:24:52688static TransportOptions GetTransportOptions(const MediaSessionOptions& options,
689 const std::string& content_name) {
Honghai Zhang4cedf2b2016-08-31 15:18:11690 TransportOptions transport_options;
deadbeef0ed85b22016-02-24 01:24:52691 auto it = options.transport_options.find(content_name);
Honghai Zhang4cedf2b2016-08-31 15:18:11692 if (it != options.transport_options.end()) {
693 transport_options = it->second;
deadbeef0ed85b22016-02-24 01:24:52694 }
Honghai Zhang4cedf2b2016-08-31 15:18:11695 transport_options.enable_ice_renomination = options.enable_ice_renomination;
696 return transport_options;
deadbeef0ed85b22016-02-24 01:24:52697}
698
henrike@webrtc.org28e20752013-07-10 00:45:36699// Create a media content to be offered in a session-initiate,
700// according to the given options.rtcp_mux, options.is_muc,
701// options.streams, codecs, secure_transport, crypto, and streams. If we don't
702// currently have crypto (in current_cryptos) and it is enabled (in
703// secure_policy), crypto is created (according to crypto_suites). If
704// add_legacy_stream is true, and current_streams is empty, a legacy
705// stream is created. The created content is added to the offer.
706template <class C>
707static bool CreateMediaContentOffer(
708 const MediaSessionOptions& options,
709 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57710 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36711 const CryptoParamsVec* current_cryptos,
712 const std::vector<std::string>& crypto_suites,
713 const RtpHeaderExtensions& rtp_extensions,
714 bool add_legacy_stream,
715 StreamParamsVec* current_streams,
716 MediaContentDescriptionImpl<C>* offer) {
717 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36718
henrike@webrtc.orgb90991d2014-03-04 19:54:57719 if (secure_policy == SEC_REQUIRED) {
720 offer->set_crypto_required(CT_SDES);
721 }
henrike@webrtc.org28e20752013-07-10 00:45:36722 offer->set_rtcp_mux(options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 22:02:07723 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
724 offer->set_rtcp_reduced_size(true);
725 }
henrike@webrtc.org28e20752013-07-10 00:45:36726 offer->set_multistream(options.is_muc);
727 offer->set_rtp_header_extensions(rtp_extensions);
728
zhihuang8f65cdf2016-05-07 01:40:30729 if (!AddStreamParams(offer->type(), options, current_streams, offer,
730 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36731 return false;
732 }
733
734#ifdef HAVE_SRTP
735 if (secure_policy != SEC_DISABLED) {
736 if (current_cryptos) {
737 AddMediaCryptos(*current_cryptos, offer);
738 }
739 if (offer->cryptos().empty()) {
740 if (!CreateMediaCryptos(crypto_suites, offer)) {
741 return false;
742 }
743 }
744 }
745#endif
746
henrike@webrtc.orgb90991d2014-03-04 19:54:57747 if (offer->crypto_required() == CT_SDES && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36748 return false;
749 }
750 return true;
751}
752
753template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34754static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
755 const std::string& codec1_id_str,
756 const std::vector<C>& codecs2,
757 const std::string& codec2_id_str) {
758 int codec1_id;
759 int codec2_id;
760 C codec1;
761 C codec2;
762 if (!rtc::FromString(codec1_id_str, &codec1_id) ||
763 !rtc::FromString(codec2_id_str, &codec2_id) ||
764 !FindCodecById(codecs1, codec1_id, &codec1) ||
765 !FindCodecById(codecs2, codec2_id, &codec2)) {
766 return false;
767 }
768 return codec1.Matches(codec2);
769}
770
771template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36772static void NegotiateCodecs(const std::vector<C>& local_codecs,
773 const std::vector<C>& offered_codecs,
774 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-05 00:47:56775 for (const C& ours : local_codecs) {
776 C theirs;
deadbeef67cf2c12016-04-13 17:07:16777 // Note that we intentionally only find one matching codec for each of our
778 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-05 00:47:56779 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
780 C negotiated = ours;
781 negotiated.IntersectFeedbackParams(theirs);
782 if (IsRtxCodec(negotiated)) {
783 std::string offered_apt_value;
784 theirs.GetParam(kCodecParamAssociatedPayloadType, &offered_apt_value);
785 // FindMatchingCodec shouldn't return something with no apt value.
786 RTC_DCHECK(!offered_apt_value.empty());
787 negotiated.SetParam(kCodecParamAssociatedPayloadType,
788 offered_apt_value);
henrike@webrtc.org28e20752013-07-10 00:45:36789 }
Taylor Brandstetter6ec641b2016-03-05 00:47:56790 negotiated.id = theirs.id;
ossu075af922016-06-14 10:29:38791 negotiated.name = theirs.name;
Taylor Brandstetter6ec641b2016-03-05 00:47:56792 negotiated_codecs->push_back(negotiated);
henrike@webrtc.org28e20752013-07-10 00:45:36793 }
794 }
deadbeef67cf2c12016-04-13 17:07:16795 // RFC3264: Although the answerer MAY list the formats in their desired
796 // order of preference, it is RECOMMENDED that unless there is a
797 // specific reason, the answerer list formats in the same relative order
798 // they were present in the offer.
799 std::unordered_map<int, int> payload_type_preferences;
800 int preference = static_cast<int>(offered_codecs.size() + 1);
801 for (const C& codec : offered_codecs) {
802 payload_type_preferences[codec.id] = preference--;
803 }
804 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
805 [&payload_type_preferences](const C& a, const C& b) {
806 return payload_type_preferences[a.id] >
807 payload_type_preferences[b.id];
808 });
henrike@webrtc.org28e20752013-07-10 00:45:36809}
810
Taylor Brandstetter6ec641b2016-03-05 00:47:56811// Finds a codec in |codecs2| that matches |codec_to_match|, which is
812// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
813// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36814template <class C>
Taylor Brandstetter6ec641b2016-03-05 00:47:56815static bool FindMatchingCodec(const std::vector<C>& codecs1,
816 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36817 const C& codec_to_match,
818 C* found_codec) {
Taylor Brandstetter6ec641b2016-03-05 00:47:56819 for (const C& potential_match : codecs2) {
820 if (potential_match.Matches(codec_to_match)) {
821 if (IsRtxCodec(codec_to_match)) {
822 std::string apt_value_1;
823 std::string apt_value_2;
824 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
825 &apt_value_1) ||
826 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
827 &apt_value_2)) {
828 LOG(LS_WARNING) << "RTX missing associated payload type.";
829 continue;
830 }
831 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
832 apt_value_2)) {
833 continue;
834 }
835 }
836 if (found_codec) {
837 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36838 }
839 return true;
840 }
841 }
842 return false;
843}
844
845// Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
846// already exist in |offered_codecs| and ensure the payload types don't
847// collide.
848template <class C>
849static void FindCodecsToOffer(
850 const std::vector<C>& reference_codecs,
851 std::vector<C>* offered_codecs,
852 UsedPayloadTypes* used_pltypes) {
853
henrike@webrtc.org28e20752013-07-10 00:45:36854 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-05 00:47:56855 for (const C& reference_codec : reference_codecs) {
856 if (!IsRtxCodec(reference_codec) &&
857 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
858 reference_codec, nullptr)) {
859 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36860 used_pltypes->FindAndSetIdUsed(&codec);
861 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36862 }
863 }
864
865 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-05 00:47:56866 for (const C& reference_codec : reference_codecs) {
867 if (IsRtxCodec(reference_codec) &&
868 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
869 reference_codec, nullptr)) {
870 C rtx_codec = reference_codec;
871
872 std::string associated_pt_str;
873 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
874 &associated_pt_str)) {
875 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
876 << " is missing an associated payload type.";
877 continue;
878 }
879
880 int associated_pt;
881 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
882 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
883 << " of RTX codec " << rtx_codec.name
884 << " to an integer.";
885 continue;
886 }
887
888 // Find the associated reference codec for the reference RTX codec.
889 C associated_codec;
890 if (!FindCodecById(reference_codecs, associated_pt, &associated_codec)) {
891 LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
892 << associated_pt << " for RTX codec " << rtx_codec.name
893 << ".";
894 continue;
895 }
896
897 // Find a codec in the offered list that matches the reference codec.
898 // Its payload type may be different than the reference codec.
899 C matching_codec;
900 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
901 associated_codec, &matching_codec)) {
902 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec.name
903 << " codec.";
904 continue;
905 }
906
907 rtx_codec.params[kCodecParamAssociatedPayloadType] =
908 rtc::ToString(matching_codec.id);
909 used_pltypes->FindAndSetIdUsed(&rtx_codec);
910 offered_codecs->push_back(rtx_codec);
911 }
henrike@webrtc.org28e20752013-07-10 00:45:36912 }
913}
914
henrike@webrtc.org28e20752013-07-10 00:45:36915static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 18:24:55916 const webrtc::RtpExtension& ext_to_match,
917 webrtc::RtpExtension* found_extension) {
henrike@webrtc.org28e20752013-07-10 00:45:36918 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
919 it != extensions.end(); ++it) {
920 // We assume that all URIs are given in a canonical format.
921 if (it->uri == ext_to_match.uri) {
922 if (found_extension != NULL) {
henrike@webrtc.org79047f92014-03-06 23:46:59923 *found_extension = *it;
henrike@webrtc.org28e20752013-07-10 00:45:36924 }
925 return true;
926 }
927 }
928 return false;
929}
930
deadbeefa5b273a2015-08-21 00:30:13931// Iterates through |offered_extensions|, adding each one to |all_extensions|
932// and |used_ids|, and resolving ID conflicts. If an offered extension has the
933// same URI as one in |all_extensions|, it will re-use the same ID and won't be
934// treated as a conflict.
935static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions,
936 RtpHeaderExtensions* all_extensions,
937 UsedRtpHeaderExtensionIds* used_ids) {
938 for (auto& extension : *offered_extensions) {
isheriff6f8d6862016-05-26 18:24:55939 webrtc::RtpExtension existing;
deadbeefa5b273a2015-08-21 00:30:13940 if (FindByUri(*all_extensions, extension, &existing)) {
941 extension.id = existing.id;
942 } else {
943 used_ids->FindAndSetIdUsed(&extension);
944 all_extensions->push_back(extension);
945 }
946 }
947}
948
949// Adds |reference_extensions| to |offered_extensions|, while updating
950// |all_extensions| and |used_ids|.
951static void FindRtpHdrExtsToOffer(
952 const RtpHeaderExtensions& reference_extensions,
953 RtpHeaderExtensions* offered_extensions,
954 RtpHeaderExtensions* all_extensions,
955 UsedRtpHeaderExtensionIds* used_ids) {
956 for (auto reference_extension : reference_extensions) {
957 if (!FindByUri(*offered_extensions, reference_extension, NULL)) {
isheriff6f8d6862016-05-26 18:24:55958 webrtc::RtpExtension existing;
deadbeefa5b273a2015-08-21 00:30:13959 if (FindByUri(*all_extensions, reference_extension, &existing)) {
960 offered_extensions->push_back(existing);
961 } else {
962 used_ids->FindAndSetIdUsed(&reference_extension);
963 all_extensions->push_back(reference_extension);
964 offered_extensions->push_back(reference_extension);
henrike@webrtc.org79047f92014-03-06 23:46:59965 }
henrike@webrtc.org28e20752013-07-10 00:45:36966 }
967 }
968}
969
970static void NegotiateRtpHeaderExtensions(
971 const RtpHeaderExtensions& local_extensions,
972 const RtpHeaderExtensions& offered_extensions,
973 RtpHeaderExtensions* negotiated_extenstions) {
974 RtpHeaderExtensions::const_iterator ours;
975 for (ours = local_extensions.begin();
976 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 18:24:55977 webrtc::RtpExtension theirs;
henrike@webrtc.org28e20752013-07-10 00:45:36978 if (FindByUri(offered_extensions, *ours, &theirs)) {
979 // We respond with their RTP header extension id.
980 negotiated_extenstions->push_back(theirs);
981 }
982 }
983}
984
985static void StripCNCodecs(AudioCodecs* audio_codecs) {
986 AudioCodecs::iterator iter = audio_codecs->begin();
987 while (iter != audio_codecs->end()) {
988 if (stricmp(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
989 iter = audio_codecs->erase(iter);
990 } else {
991 ++iter;
992 }
993 }
994}
995
996// Create a media content to be answered in a session-accept,
997// according to the given options.rtcp_mux, options.streams, codecs,
998// crypto, and streams. If we don't currently have crypto (in
999// current_cryptos) and it is enabled (in secure_policy), crypto is
1000// created (according to crypto_suites). If add_legacy_stream is
1001// true, and current_streams is empty, a legacy stream is created.
1002// The codecs, rtcp_mux, and crypto are all negotiated with the offer
1003// from the incoming session-initiate. If the negotiation fails, this
1004// method returns false. The created content is added to the offer.
1005template <class C>
1006static bool CreateMediaContentAnswer(
1007 const MediaContentDescriptionImpl<C>* offer,
1008 const MediaSessionOptions& options,
1009 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:571010 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:361011 const CryptoParamsVec* current_cryptos,
1012 const RtpHeaderExtensions& local_rtp_extenstions,
1013 StreamParamsVec* current_streams,
1014 bool add_legacy_stream,
1015 bool bundle_enabled,
1016 MediaContentDescriptionImpl<C>* answer) {
1017 std::vector<C> negotiated_codecs;
1018 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1019 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:361020 answer->set_protocol(offer->protocol());
1021 RtpHeaderExtensions negotiated_rtp_extensions;
1022 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1023 offer->rtp_header_extensions(),
1024 &negotiated_rtp_extensions);
1025 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1026
1027 answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 22:02:071028 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1029 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1030 }
henrike@webrtc.org28e20752013-07-10 00:45:361031
1032 if (sdes_policy != SEC_DISABLED) {
1033 CryptoParams crypto;
jbauchcb560652016-08-04 12:20:321034 if (SelectCrypto(offer, bundle_enabled, options.crypto_options, &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:361035 if (current_cryptos) {
1036 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1037 }
1038 answer->AddCrypto(crypto);
1039 }
1040 }
1041
1042 if (answer->cryptos().empty() &&
henrike@webrtc.orgb90991d2014-03-04 19:54:571043 (offer->crypto_required() == CT_SDES || sdes_policy == SEC_REQUIRED)) {
henrike@webrtc.org28e20752013-07-10 00:45:361044 return false;
1045 }
1046
zhihuang8f65cdf2016-05-07 01:40:301047 if (!AddStreamParams(answer->type(), options, current_streams, answer,
1048 add_legacy_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:361049 return false; // Something went seriously wrong.
1050 }
1051
1052 // Make sure the answer media content direction is per default set as
1053 // described in RFC3264 section 6.1.
ossu075af922016-06-14 10:29:381054 const bool is_data = !IsRtpProtocol(answer->protocol());
1055 const bool has_send_streams = !answer->streams().empty();
1056 const bool wants_send = has_send_streams || is_data;
1057 const bool recv_audio =
1058 answer->type() == cricket::MEDIA_TYPE_AUDIO && options.recv_audio;
1059 const bool recv_video =
1060 answer->type() == cricket::MEDIA_TYPE_VIDEO && options.recv_video;
1061 const bool recv_data =
1062 answer->type() == cricket::MEDIA_TYPE_DATA;
1063 const bool wants_receive = recv_audio || recv_video || recv_data;
henrike@webrtc.org28e20752013-07-10 00:45:361064
ossu075af922016-06-14 10:29:381065 auto offer_rtd =
1066 RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
1067 auto wants_rtd = RtpTransceiverDirection(wants_send, wants_receive);
1068 answer->set_direction(NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd)
1069 .ToMediaContentDirection());
henrike@webrtc.org28e20752013-07-10 00:45:361070 return true;
1071}
1072
zhihuangcf5b37c2016-05-05 18:44:351073static bool IsDtlsRtp(const std::string& protocol) {
1074 // Most-likely values first.
1075 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
1076 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
1077}
1078
1079static bool IsPlainRtp(const std::string& protocol) {
1080 // Most-likely values first.
1081 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
1082 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
1083}
1084
1085static bool IsDtlsSctp(const std::string& protocol) {
1086 return protocol == "DTLS/SCTP";
1087}
1088
1089static bool IsPlainSctp(const std::string& protocol) {
1090 return protocol == "SCTP";
1091}
1092
henrike@webrtc.org28e20752013-07-10 00:45:361093static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:591094 const std::string& protocol,
1095 bool secure_transport) {
zhihuangcf5b37c2016-05-05 18:44:351096 // Since not all applications serialize and deserialize the media protocol,
1097 // we will have to accept |protocol| to be empty.
1098 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:361099 return true;
1100 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:591101
zhihuangcf5b37c2016-05-05 18:44:351102 if (type == MEDIA_TYPE_DATA) {
1103 // Check for SCTP, but also for RTP for RTP-based data channels.
1104 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1105 if (secure_transport) {
1106 // Most likely scenarios first.
1107 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1108 IsPlainRtp(protocol);
1109 } else {
1110 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1111 }
1112 }
1113
1114 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1115 // JSEP specifies.
1116 if (secure_transport) {
1117 // Most likely scenarios first.
1118 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1119 } else {
1120 return IsPlainRtp(protocol);
1121 }
henrike@webrtc.org28e20752013-07-10 00:45:361122}
1123
1124static void SetMediaProtocol(bool secure_transport,
1125 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 19:20:531126 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:361127 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 19:20:531128 else if (secure_transport)
1129 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:361130 else
1131 desc->set_protocol(kMediaProtocolAvpf);
1132}
1133
mallinath@webrtc.org19f27e62013-10-13 17:18:271134// Gets the TransportInfo of the given |content_name| from the
1135// |current_description|. If doesn't exist, returns a new one.
1136static const TransportDescription* GetTransportDescription(
1137 const std::string& content_name,
1138 const SessionDescription* current_description) {
1139 const TransportDescription* desc = NULL;
1140 if (current_description) {
1141 const TransportInfo* info =
1142 current_description->GetTransportInfoByName(content_name);
1143 if (info) {
1144 desc = &info->description;
1145 }
1146 }
1147 return desc;
1148}
1149
1150// Gets the current DTLS state from the transport description.
1151static bool IsDtlsActive(
1152 const std::string& content_name,
1153 const SessionDescription* current_description) {
1154 if (!current_description)
1155 return false;
1156
1157 const ContentInfo* content =
1158 current_description->GetContentByName(content_name);
1159 if (!content)
1160 return false;
1161
1162 const TransportDescription* current_tdesc =
1163 GetTransportDescription(content_name, current_description);
1164 if (!current_tdesc)
1165 return false;
1166
1167 return current_tdesc->secure();
1168}
1169
sergeyu@chromium.org4b26e2e2014-01-15 23:15:541170std::string MediaTypeToString(MediaType type) {
1171 std::string type_str;
1172 switch (type) {
1173 case MEDIA_TYPE_AUDIO:
1174 type_str = "audio";
1175 break;
1176 case MEDIA_TYPE_VIDEO:
1177 type_str = "video";
1178 break;
1179 case MEDIA_TYPE_DATA:
1180 type_str = "data";
1181 break;
1182 default:
1183 ASSERT(false);
1184 break;
1185 }
1186 return type_str;
1187}
1188
ossu075af922016-06-14 10:29:381189std::string MediaContentDirectionToString(MediaContentDirection direction) {
1190 std::string dir_str;
1191 switch (direction) {
1192 case MD_INACTIVE:
1193 dir_str = "inactive";
1194 break;
1195 case MD_SENDONLY:
1196 dir_str = "sendonly";
1197 break;
1198 case MD_RECVONLY:
1199 dir_str = "recvonly";
1200 break;
1201 case MD_SENDRECV:
1202 dir_str = "sendrecv";
1203 break;
1204 default:
1205 ASSERT(false);
1206 break;
1207 }
1208
1209 return dir_str;
1210}
1211
jiayl@webrtc.org742922b2014-10-07 21:32:431212void MediaSessionOptions::AddSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:361213 const std::string& id,
1214 const std::string& sync_label) {
jiayl@webrtc.org742922b2014-10-07 21:32:431215 AddSendStreamInternal(type, id, sync_label, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:121216}
1217
jiayl@webrtc.org742922b2014-10-07 21:32:431218void MediaSessionOptions::AddSendVideoStream(
wu@webrtc.orgcecfd182013-10-30 05:18:121219 const std::string& id,
1220 const std::string& sync_label,
1221 int num_sim_layers) {
jiayl@webrtc.org742922b2014-10-07 21:32:431222 AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:121223}
1224
jiayl@webrtc.org742922b2014-10-07 21:32:431225void MediaSessionOptions::AddSendStreamInternal(
wu@webrtc.orgcecfd182013-10-30 05:18:121226 MediaType type,
1227 const std::string& id,
1228 const std::string& sync_label,
1229 int num_sim_layers) {
1230 streams.push_back(Stream(type, id, sync_label, num_sim_layers));
henrike@webrtc.org28e20752013-07-10 00:45:361231
henrike@webrtc.org28e20752013-07-10 00:45:361232 // If we haven't already set the data_channel_type, and we add a
1233 // stream, we assume it's an RTP data stream.
jiayl@webrtc.org742922b2014-10-07 21:32:431234 if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
henrike@webrtc.org28e20752013-07-10 00:45:361235 data_channel_type = DCT_RTP;
1236}
1237
jiayl@webrtc.org742922b2014-10-07 21:32:431238void MediaSessionOptions::RemoveSendStream(MediaType type,
henrike@webrtc.org28e20752013-07-10 00:45:361239 const std::string& id) {
1240 Streams::iterator stream_it = streams.begin();
1241 for (; stream_it != streams.end(); ++stream_it) {
1242 if (stream_it->type == type && stream_it->id == id) {
1243 streams.erase(stream_it);
1244 return;
1245 }
1246 }
1247 ASSERT(false);
1248}
1249
jiayl@webrtc.org742922b2014-10-07 21:32:431250bool MediaSessionOptions::HasSendMediaStream(MediaType type) const {
1251 Streams::const_iterator stream_it = streams.begin();
1252 for (; stream_it != streams.end(); ++stream_it) {
1253 if (stream_it->type == type) {
1254 return true;
1255 }
1256 }
1257 return false;
1258}
1259
henrike@webrtc.org28e20752013-07-10 00:45:361260MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1261 const TransportDescriptionFactory* transport_desc_factory)
1262 : secure_(SEC_DISABLED),
1263 add_legacy_(true),
1264 transport_desc_factory_(transport_desc_factory) {
1265}
1266
1267MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1268 ChannelManager* channel_manager,
1269 const TransportDescriptionFactory* transport_desc_factory)
1270 : secure_(SEC_DISABLED),
1271 add_legacy_(true),
1272 transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 14:12:391273 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1274 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
1275 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:361276 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 11:36:531277 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:361278 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1279 channel_manager->GetSupportedDataCodecs(&data_codecs_);
ossudedfd282016-06-14 14:12:391280 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
1281 &audio_sendrecv_codecs_);
ossu075af922016-06-14 10:29:381282}
1283
ossudedfd282016-06-14 14:12:391284const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1285 const {
ossu075af922016-06-14 10:29:381286 return audio_sendrecv_codecs_;
1287}
1288
1289const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1290 return audio_send_codecs_;
1291}
1292
1293const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1294 return audio_recv_codecs_;
1295}
1296
1297void MediaSessionDescriptionFactory::set_audio_codecs(
1298 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1299 audio_send_codecs_ = send_codecs;
1300 audio_recv_codecs_ = recv_codecs;
1301 audio_sendrecv_codecs_.clear();
1302 // Use NegotiateCodecs to merge our codec lists, since the operation is
1303 // essentially the same. Put send_codecs as the offered_codecs, which is the
1304 // order we'd like to follow. The reasoning is that encoding is usually more
1305 // expensive than decoding, and prioritizing a codec in the send list probably
1306 // means it's a codec we can handle efficiently.
1307 NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:361308}
1309
1310SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
1311 const MediaSessionOptions& options,
1312 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 22:18:211313 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:361314
1315 StreamParamsVec current_streams;
1316 GetCurrentStreamParams(current_description, &current_streams);
1317
ossu075af922016-06-14 10:29:381318 const bool wants_send =
1319 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1320 const AudioCodecs& supported_audio_codecs =
1321 GetAudioCodecsForOffer({wants_send, options.recv_audio});
1322
henrike@webrtc.org28e20752013-07-10 00:45:361323 AudioCodecs audio_codecs;
1324 VideoCodecs video_codecs;
1325 DataCodecs data_codecs;
ossu075af922016-06-14 10:29:381326 GetCodecsToOffer(current_description, supported_audio_codecs,
1327 video_codecs_, data_codecs_,
1328 &audio_codecs, &video_codecs, &data_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:361329
1330 if (!options.vad_enabled) {
1331 // If application doesn't want CN codecs in offer.
1332 StripCNCodecs(&audio_codecs);
1333 }
1334
1335 RtpHeaderExtensions audio_rtp_extensions;
1336 RtpHeaderExtensions video_rtp_extensions;
1337 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1338 &video_rtp_extensions);
1339
jiayl@webrtc.orge7d47a12014-08-05 19:19:051340 bool audio_added = false;
1341 bool video_added = false;
1342 bool data_added = false;
mallinath@webrtc.org19f27e62013-10-13 17:18:271343
jiayl@webrtc.orge7d47a12014-08-05 19:19:051344 // Iterate through the contents of |current_description| to maintain the order
1345 // of the m-lines in the new offer.
1346 if (current_description) {
1347 ContentInfos::const_iterator it = current_description->contents().begin();
1348 for (; it != current_description->contents().end(); ++it) {
jiayl@webrtc.org7d4891d2014-09-09 21:43:151349 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:051350 if (!AddAudioContentForOffer(options, current_description,
1351 audio_rtp_extensions, audio_codecs,
1352 &current_streams, offer.get())) {
1353 return NULL;
1354 }
1355 audio_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:151356 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:051357 if (!AddVideoContentForOffer(options, current_description,
1358 video_rtp_extensions, video_codecs,
1359 &current_streams, offer.get())) {
1360 return NULL;
1361 }
1362 video_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:151363 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) {
tommi@webrtc.orgf15dee62014-10-27 22:15:041364 MediaSessionOptions options_copy(options);
1365 if (IsSctp(static_cast<const MediaContentDescription*>(
1366 it->description))) {
1367 options_copy.data_channel_type = DCT_SCTP;
1368 }
1369 if (!AddDataContentForOffer(options_copy, current_description,
1370 &data_codecs, &current_streams,
1371 offer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:051372 return NULL;
1373 }
1374 data_added = true;
jiayl@webrtc.org7d4891d2014-09-09 21:43:151375 } else {
1376 ASSERT(false);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051377 }
henrike@webrtc.org28e20752013-07-10 00:45:361378 }
1379 }
jiayl@webrtc.org742922b2014-10-07 21:32:431380
jiayl@webrtc.orge7d47a12014-08-05 19:19:051381 // Append contents that are not in |current_description|.
jiayl@webrtc.org742922b2014-10-07 21:32:431382 if (!audio_added && options.has_audio() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:051383 !AddAudioContentForOffer(options, current_description,
1384 audio_rtp_extensions, audio_codecs,
1385 &current_streams, offer.get())) {
1386 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:361387 }
jiayl@webrtc.org742922b2014-10-07 21:32:431388 if (!video_added && options.has_video() &&
jiayl@webrtc.orge7d47a12014-08-05 19:19:051389 !AddVideoContentForOffer(options, current_description,
1390 video_rtp_extensions, video_codecs,
1391 &current_streams, offer.get())) {
1392 return NULL;
1393 }
1394 if (!data_added && options.has_data() &&
1395 !AddDataContentForOffer(options, current_description, &data_codecs,
1396 &current_streams, offer.get())) {
1397 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:361398 }
1399
1400 // Bundle the contents together, if we've been asked to do so, and update any
1401 // parameters that need to be tweaked for BUNDLE.
1402 if (options.bundle_enabled) {
1403 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
1404 for (ContentInfos::const_iterator content = offer->contents().begin();
1405 content != offer->contents().end(); ++content) {
1406 offer_bundle.AddContentName(content->name);
1407 }
1408 offer->AddGroup(offer_bundle);
1409 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1410 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
1411 return NULL;
1412 }
1413 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1414 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
1415 return NULL;
1416 }
1417 }
1418
1419 return offer.release();
1420}
1421
1422SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
1423 const SessionDescription* offer, const MediaSessionOptions& options,
1424 const SessionDescription* current_description) const {
1425 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 17:07:161426 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1427 // from the offer in the answer.
kwiberg31022942016-03-11 22:18:211428 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:361429
1430 StreamParamsVec current_streams;
1431 GetCurrentStreamParams(current_description, &current_streams);
1432
jiayl@webrtc.orge7d47a12014-08-05 19:19:051433 if (offer) {
1434 ContentInfos::const_iterator it = offer->contents().begin();
1435 for (; it != offer->contents().end(); ++it) {
1436 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
1437 if (!AddAudioContentForAnswer(offer, options, current_description,
1438 &current_streams, answer.get())) {
1439 return NULL;
1440 }
1441 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
1442 if (!AddVideoContentForAnswer(offer, options, current_description,
1443 &current_streams, answer.get())) {
1444 return NULL;
1445 }
1446 } else {
1447 ASSERT(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA));
1448 if (!AddDataContentForAnswer(offer, options, current_description,
1449 &current_streams, answer.get())) {
1450 return NULL;
1451 }
henrike@webrtc.org28e20752013-07-10 00:45:361452 }
henrike@webrtc.org28e20752013-07-10 00:45:361453 }
henrike@webrtc.org28e20752013-07-10 00:45:361454 }
1455
1456 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1457 // group in the answer with the appropriate content names.
1458 if (offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled) {
1459 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1460 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1461 for (ContentInfos::const_iterator content = answer->contents().begin();
1462 content != answer->contents().end(); ++content) {
1463 if (!content->rejected && offer_bundle->HasContentName(content->name)) {
1464 answer_bundle.AddContentName(content->name);
1465 }
1466 }
1467 if (answer_bundle.FirstContentName()) {
1468 answer->AddGroup(answer_bundle);
1469
1470 // Share the same ICE credentials and crypto params across all contents,
1471 // as BUNDLE requires.
1472 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1473 LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1474 return NULL;
1475 }
1476
1477 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1478 LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1479 return NULL;
1480 }
1481 }
1482 }
1483
1484 return answer.release();
1485}
1486
ossu075af922016-06-14 10:29:381487const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1488 const RtpTransceiverDirection& direction) const {
1489 // If stream is inactive - generate list as if sendrecv.
1490 if (direction.send == direction.recv) {
1491 return audio_sendrecv_codecs_;
1492 } else if (direction.send) {
1493 return audio_send_codecs_;
1494 } else {
1495 return audio_recv_codecs_;
1496 }
1497}
1498
1499const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1500 const RtpTransceiverDirection& offer,
1501 const RtpTransceiverDirection& answer) const {
1502 // For inactive and sendrecv answers, generate lists as if we were to accept
1503 // the offer's direction. See RFC 3264 Section 6.1.
1504 if (answer.send == answer.recv) {
1505 if (offer.send == offer.recv) {
1506 return audio_sendrecv_codecs_;
1507 } else if (offer.send) {
1508 return audio_recv_codecs_;
1509 } else {
1510 return audio_send_codecs_;
1511 }
1512 } else if (answer.send) {
1513 return audio_send_codecs_;
1514 } else {
1515 return audio_recv_codecs_;
1516 }
1517}
1518
henrike@webrtc.org28e20752013-07-10 00:45:361519void MediaSessionDescriptionFactory::GetCodecsToOffer(
1520 const SessionDescription* current_description,
ossu075af922016-06-14 10:29:381521 const AudioCodecs& supported_audio_codecs,
1522 const VideoCodecs& supported_video_codecs,
1523 const DataCodecs& supported_data_codecs,
henrike@webrtc.org28e20752013-07-10 00:45:361524 AudioCodecs* audio_codecs,
1525 VideoCodecs* video_codecs,
1526 DataCodecs* data_codecs) const {
1527 UsedPayloadTypes used_pltypes;
1528 audio_codecs->clear();
1529 video_codecs->clear();
1530 data_codecs->clear();
1531
1532
1533 // First - get all codecs from the current description if the media type
1534 // is used.
1535 // Add them to |used_pltypes| so the payloadtype is not reused if a new media
1536 // type is added.
1537 if (current_description) {
1538 const AudioContentDescription* audio =
1539 GetFirstAudioContentDescription(current_description);
1540 if (audio) {
1541 *audio_codecs = audio->codecs();
1542 used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
1543 }
1544 const VideoContentDescription* video =
1545 GetFirstVideoContentDescription(current_description);
1546 if (video) {
1547 *video_codecs = video->codecs();
1548 used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
1549 }
1550 const DataContentDescription* data =
1551 GetFirstDataContentDescription(current_description);
1552 if (data) {
1553 *data_codecs = data->codecs();
1554 used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
1555 }
1556 }
1557
1558 // Add our codecs that are not in |current_description|.
ossu075af922016-06-14 10:29:381559 FindCodecsToOffer<AudioCodec>(supported_audio_codecs, audio_codecs,
1560 &used_pltypes);
1561 FindCodecsToOffer<VideoCodec>(supported_video_codecs, video_codecs,
1562 &used_pltypes);
1563 FindCodecsToOffer<DataCodec>(supported_data_codecs, data_codecs,
1564 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:361565}
1566
1567void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1568 const SessionDescription* current_description,
1569 RtpHeaderExtensions* audio_extensions,
1570 RtpHeaderExtensions* video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:591571 // All header extensions allocated from the same range to avoid potential
1572 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:361573 UsedRtpHeaderExtensionIds used_ids;
deadbeefa5b273a2015-08-21 00:30:131574 RtpHeaderExtensions all_extensions;
henrike@webrtc.org28e20752013-07-10 00:45:361575 audio_extensions->clear();
1576 video_extensions->clear();
1577
1578 // First - get all extensions from the current description if the media type
1579 // is used.
1580 // Add them to |used_ids| so the local ids are not reused if a new media
1581 // type is added.
1582 if (current_description) {
1583 const AudioContentDescription* audio =
1584 GetFirstAudioContentDescription(current_description);
1585 if (audio) {
1586 *audio_extensions = audio->rtp_header_extensions();
deadbeefa5b273a2015-08-21 00:30:131587 FindAndSetRtpHdrExtUsed(audio_extensions, &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:361588 }
1589 const VideoContentDescription* video =
1590 GetFirstVideoContentDescription(current_description);
1591 if (video) {
1592 *video_extensions = video->rtp_header_extensions();
deadbeefa5b273a2015-08-21 00:30:131593 FindAndSetRtpHdrExtUsed(video_extensions, &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:361594 }
1595 }
1596
1597 // Add our default RTP header extensions that are not in
1598 // |current_description|.
deadbeefa5b273a2015-08-21 00:30:131599 FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions,
1600 &all_extensions, &used_ids);
1601 FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions,
1602 &all_extensions, &used_ids);
henrike@webrtc.org28e20752013-07-10 00:45:361603}
1604
1605bool MediaSessionDescriptionFactory::AddTransportOffer(
1606 const std::string& content_name,
1607 const TransportOptions& transport_options,
1608 const SessionDescription* current_desc,
1609 SessionDescription* offer_desc) const {
1610 if (!transport_desc_factory_)
1611 return false;
1612 const TransportDescription* current_tdesc =
1613 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 22:18:211614 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:361615 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1616 bool ret = (new_tdesc.get() != NULL &&
1617 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1618 if (!ret) {
1619 LOG(LS_ERROR)
1620 << "Failed to AddTransportOffer, content name=" << content_name;
1621 }
1622 return ret;
1623}
1624
1625TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1626 const std::string& content_name,
1627 const SessionDescription* offer_desc,
1628 const TransportOptions& transport_options,
1629 const SessionDescription* current_desc) const {
1630 if (!transport_desc_factory_)
1631 return NULL;
1632 const TransportDescription* offer_tdesc =
1633 GetTransportDescription(content_name, offer_desc);
1634 const TransportDescription* current_tdesc =
1635 GetTransportDescription(content_name, current_desc);
1636 return
1637 transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1638 current_tdesc);
1639}
1640
1641bool MediaSessionDescriptionFactory::AddTransportAnswer(
1642 const std::string& content_name,
1643 const TransportDescription& transport_desc,
1644 SessionDescription* answer_desc) const {
1645 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1646 transport_desc))) {
1647 LOG(LS_ERROR)
1648 << "Failed to AddTransportAnswer, content name=" << content_name;
1649 return false;
1650 }
1651 return true;
1652}
1653
jiayl@webrtc.orge7d47a12014-08-05 19:19:051654bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
1655 const MediaSessionOptions& options,
1656 const SessionDescription* current_description,
1657 const RtpHeaderExtensions& audio_rtp_extensions,
1658 const AudioCodecs& audio_codecs,
1659 StreamParamsVec* current_streams,
1660 SessionDescription* desc) const {
deadbeef44f08192015-12-16 00:20:091661 const ContentInfo* current_audio_content =
1662 GetFirstAudioContent(current_description);
1663 std::string content_name =
1664 current_audio_content ? current_audio_content->name : CN_AUDIO;
1665
jiayl@webrtc.orge7d47a12014-08-05 19:19:051666 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-16 00:20:091667 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1668 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:051669
kwiberg31022942016-03-11 22:18:211670 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:051671 std::vector<std::string> crypto_suites;
jbauchcb560652016-08-04 12:20:321672 GetSupportedAudioCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051673 if (!CreateMediaContentOffer(
1674 options,
1675 audio_codecs,
1676 sdes_policy,
1677 GetCryptos(GetFirstAudioContentDescription(current_description)),
1678 crypto_suites,
1679 audio_rtp_extensions,
1680 add_legacy_,
1681 current_streams,
1682 audio.get())) {
1683 return false;
1684 }
1685 audio->set_lang(lang_);
1686
1687 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1688 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:151689
ossu075af922016-06-14 10:29:381690 auto offer_rtd =
1691 RtpTransceiverDirection(!audio->streams().empty(), options.recv_audio);
1692 audio->set_direction(offer_rtd.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:431693
deadbeef44f08192015-12-16 00:20:091694 desc->AddContent(content_name, NS_JINGLE_RTP, audio.release());
deadbeef0ed85b22016-02-24 01:24:521695 if (!AddTransportOffer(content_name,
1696 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:051697 current_description, desc)) {
1698 return false;
1699 }
1700
1701 return true;
1702}
1703
1704bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
1705 const MediaSessionOptions& options,
1706 const SessionDescription* current_description,
1707 const RtpHeaderExtensions& video_rtp_extensions,
1708 const VideoCodecs& video_codecs,
1709 StreamParamsVec* current_streams,
1710 SessionDescription* desc) const {
deadbeef44f08192015-12-16 00:20:091711 const ContentInfo* current_video_content =
1712 GetFirstVideoContent(current_description);
1713 std::string content_name =
1714 current_video_content ? current_video_content->name : CN_VIDEO;
1715
jiayl@webrtc.orge7d47a12014-08-05 19:19:051716 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-16 00:20:091717 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1718 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:051719
kwiberg31022942016-03-11 22:18:211720 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:051721 std::vector<std::string> crypto_suites;
jbauchcb560652016-08-04 12:20:321722 GetSupportedVideoCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051723 if (!CreateMediaContentOffer(
1724 options,
1725 video_codecs,
1726 sdes_policy,
1727 GetCryptos(GetFirstVideoContentDescription(current_description)),
1728 crypto_suites,
1729 video_rtp_extensions,
1730 add_legacy_,
1731 current_streams,
1732 video.get())) {
1733 return false;
1734 }
1735
1736 video->set_bandwidth(options.video_bandwidth);
1737
1738 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1739 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:431740
deadbeefc80741f2015-10-22 20:14:451741 if (!video->streams().empty()) {
1742 if (options.recv_video) {
1743 video->set_direction(MD_SENDRECV);
1744 } else {
1745 video->set_direction(MD_SENDONLY);
1746 }
1747 } else {
1748 if (options.recv_video) {
1749 video->set_direction(MD_RECVONLY);
1750 } else {
1751 video->set_direction(MD_INACTIVE);
1752 }
jiayl@webrtc.org742922b2014-10-07 21:32:431753 }
1754
deadbeef44f08192015-12-16 00:20:091755 desc->AddContent(content_name, NS_JINGLE_RTP, video.release());
deadbeef0ed85b22016-02-24 01:24:521756 if (!AddTransportOffer(content_name,
1757 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:051758 current_description, desc)) {
1759 return false;
1760 }
1761
1762 return true;
1763}
1764
1765bool MediaSessionDescriptionFactory::AddDataContentForOffer(
1766 const MediaSessionOptions& options,
1767 const SessionDescription* current_description,
1768 DataCodecs* data_codecs,
1769 StreamParamsVec* current_streams,
1770 SessionDescription* desc) const {
1771 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1772
kwiberg31022942016-03-11 22:18:211773 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:051774 bool is_sctp = (options.data_channel_type == DCT_SCTP);
1775
1776 FilterDataCodecs(data_codecs, is_sctp);
1777
deadbeef44f08192015-12-16 00:20:091778 const ContentInfo* current_data_content =
1779 GetFirstDataContent(current_description);
1780 std::string content_name =
1781 current_data_content ? current_data_content->name : CN_DATA;
1782
jiayl@webrtc.orge7d47a12014-08-05 19:19:051783 cricket::SecurePolicy sdes_policy =
deadbeef44f08192015-12-16 00:20:091784 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
1785 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:051786 std::vector<std::string> crypto_suites;
1787 if (is_sctp) {
1788 // SDES doesn't make sense for SCTP, so we disable it, and we only
1789 // get SDES crypto suites for RTP-based data channels.
1790 sdes_policy = cricket::SEC_DISABLED;
1791 // Unlike SetMediaProtocol below, we need to set the protocol
1792 // before we call CreateMediaContentOffer. Otherwise,
1793 // CreateMediaContentOffer won't know this is SCTP and will
1794 // generate SSRCs rather than SIDs.
1795 data->set_protocol(
1796 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
1797 } else {
jbauchcb560652016-08-04 12:20:321798 GetSupportedDataCryptoSuiteNames(options.crypto_options, &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051799 }
1800
1801 if (!CreateMediaContentOffer(
1802 options,
1803 *data_codecs,
1804 sdes_policy,
1805 GetCryptos(GetFirstDataContentDescription(current_description)),
1806 crypto_suites,
1807 RtpHeaderExtensions(),
1808 add_legacy_,
1809 current_streams,
1810 data.get())) {
1811 return false;
1812 }
1813
1814 if (is_sctp) {
deadbeef44f08192015-12-16 00:20:091815 desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:051816 } else {
1817 data->set_bandwidth(options.data_bandwidth);
1818 SetMediaProtocol(secure_transport, data.get());
deadbeef44f08192015-12-16 00:20:091819 desc->AddContent(content_name, NS_JINGLE_RTP, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:051820 }
deadbeef0ed85b22016-02-24 01:24:521821 if (!AddTransportOffer(content_name,
1822 GetTransportOptions(options, content_name),
jiayl@webrtc.orge7d47a12014-08-05 19:19:051823 current_description, desc)) {
1824 return false;
1825 }
1826 return true;
1827}
1828
1829bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
1830 const SessionDescription* offer,
1831 const MediaSessionOptions& options,
1832 const SessionDescription* current_description,
1833 StreamParamsVec* current_streams,
1834 SessionDescription* answer) const {
1835 const ContentInfo* audio_content = GetFirstAudioContent(offer);
ossu075af922016-06-14 10:29:381836 const AudioContentDescription* offer_audio =
1837 static_cast<const AudioContentDescription*>(audio_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051838
kwiberg31022942016-03-11 22:18:211839 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
deadbeef0ed85b22016-02-24 01:24:521840 audio_content->name, offer,
1841 GetTransportOptions(options, audio_content->name), current_description));
jiayl@webrtc.orge7d47a12014-08-05 19:19:051842 if (!audio_transport) {
1843 return false;
1844 }
1845
ossu075af922016-06-14 10:29:381846 // Pick codecs based on the requested communications direction in the offer.
1847 const bool wants_send =
1848 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
1849 auto wants_rtd = RtpTransceiverDirection(wants_send, options.recv_audio);
1850 auto offer_rtd =
1851 RtpTransceiverDirection::FromMediaContentDirection(
1852 offer_audio->direction());
1853 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
1854 AudioCodecs audio_codecs = GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
jiayl@webrtc.orge7d47a12014-08-05 19:19:051855 if (!options.vad_enabled) {
1856 StripCNCodecs(&audio_codecs);
1857 }
1858
1859 bool bundle_enabled =
1860 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
kwiberg31022942016-03-11 22:18:211861 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:051862 new AudioContentDescription());
1863 // Do not require or create SDES cryptos if DTLS is used.
1864 cricket::SecurePolicy sdes_policy =
1865 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
1866 if (!CreateMediaContentAnswer(
ossu075af922016-06-14 10:29:381867 offer_audio,
jiayl@webrtc.orge7d47a12014-08-05 19:19:051868 options,
1869 audio_codecs,
1870 sdes_policy,
1871 GetCryptos(GetFirstAudioContentDescription(current_description)),
1872 audio_rtp_extensions_,
1873 current_streams,
1874 add_legacy_,
1875 bundle_enabled,
1876 audio_answer.get())) {
1877 return false; // Fails the session setup.
1878 }
1879
jiayl@webrtc.org742922b2014-10-07 21:32:431880 bool rejected = !options.has_audio() || audio_content->rejected ||
jiayl@webrtc.orge7d47a12014-08-05 19:19:051881 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
1882 audio_answer->protocol(),
1883 audio_transport->secure());
1884 if (!rejected) {
1885 AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer);
1886 } else {
1887 // RFC 3264
1888 // The answer MUST contain the same number of m-lines as the offer.
1889 LOG(LS_INFO) << "Audio is not supported in the answer.";
1890 }
1891
1892 answer->AddContent(audio_content->name, audio_content->type, rejected,
1893 audio_answer.release());
1894 return true;
1895}
1896
1897bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
1898 const SessionDescription* offer,
1899 const MediaSessionOptions& options,
1900 const SessionDescription* current_description,
1901 StreamParamsVec* current_streams,
1902 SessionDescription* answer) const {
1903 const ContentInfo* video_content = GetFirstVideoContent(offer);
kwiberg31022942016-03-11 22:18:211904 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer(
deadbeef0ed85b22016-02-24 01:24:521905 video_content->name, offer,
1906 GetTransportOptions(options, video_content->name), current_description));
jiayl@webrtc.orge7d47a12014-08-05 19:19:051907 if (!video_transport) {
1908 return false;
1909 }
1910
kwiberg31022942016-03-11 22:18:211911 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:051912 new VideoContentDescription());
1913 // Do not require or create SDES cryptos if DTLS is used.
1914 cricket::SecurePolicy sdes_policy =
1915 video_transport->secure() ? cricket::SEC_DISABLED : secure();
1916 bool bundle_enabled =
1917 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
1918 if (!CreateMediaContentAnswer(
1919 static_cast<const VideoContentDescription*>(
1920 video_content->description),
1921 options,
1922 video_codecs_,
1923 sdes_policy,
1924 GetCryptos(GetFirstVideoContentDescription(current_description)),
1925 video_rtp_extensions_,
1926 current_streams,
1927 add_legacy_,
1928 bundle_enabled,
1929 video_answer.get())) {
1930 return false;
1931 }
jiayl@webrtc.org742922b2014-10-07 21:32:431932 bool rejected = !options.has_video() || video_content->rejected ||
jiayl@webrtc.orge7d47a12014-08-05 19:19:051933 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
1934 video_answer->protocol(),
1935 video_transport->secure());
1936 if (!rejected) {
1937 if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
1938 answer)) {
1939 return false;
1940 }
1941 video_answer->set_bandwidth(options.video_bandwidth);
1942 } else {
1943 // RFC 3264
1944 // The answer MUST contain the same number of m-lines as the offer.
1945 LOG(LS_INFO) << "Video is not supported in the answer.";
1946 }
1947 answer->AddContent(video_content->name, video_content->type, rejected,
1948 video_answer.release());
1949 return true;
1950}
1951
1952bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
1953 const SessionDescription* offer,
1954 const MediaSessionOptions& options,
1955 const SessionDescription* current_description,
1956 StreamParamsVec* current_streams,
1957 SessionDescription* answer) const {
1958 const ContentInfo* data_content = GetFirstDataContent(offer);
kwiberg31022942016-03-11 22:18:211959 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer(
deadbeef0ed85b22016-02-24 01:24:521960 data_content->name, offer,
1961 GetTransportOptions(options, data_content->name), current_description));
jiayl@webrtc.orge7d47a12014-08-05 19:19:051962 if (!data_transport) {
1963 return false;
1964 }
1965 bool is_sctp = (options.data_channel_type == DCT_SCTP);
1966 std::vector<DataCodec> data_codecs(data_codecs_);
1967 FilterDataCodecs(&data_codecs, is_sctp);
1968
kwiberg31022942016-03-11 22:18:211969 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:051970 new DataContentDescription());
1971 // Do not require or create SDES cryptos if DTLS is used.
1972 cricket::SecurePolicy sdes_policy =
1973 data_transport->secure() ? cricket::SEC_DISABLED : secure();
1974 bool bundle_enabled =
1975 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
1976 if (!CreateMediaContentAnswer(
1977 static_cast<const DataContentDescription*>(
1978 data_content->description),
1979 options,
1980 data_codecs_,
1981 sdes_policy,
1982 GetCryptos(GetFirstDataContentDescription(current_description)),
1983 RtpHeaderExtensions(),
1984 current_streams,
1985 add_legacy_,
1986 bundle_enabled,
1987 data_answer.get())) {
1988 return false; // Fails the session setup.
1989 }
1990
1991 bool rejected = !options.has_data() || data_content->rejected ||
1992 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
1993 data_answer->protocol(),
1994 data_transport->secure());
1995 if (!rejected) {
1996 data_answer->set_bandwidth(options.data_bandwidth);
1997 if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
1998 answer)) {
1999 return false;
2000 }
2001 } else {
2002 // RFC 3264
2003 // The answer MUST contain the same number of m-lines as the offer.
2004 LOG(LS_INFO) << "Data is not supported in the answer.";
2005 }
2006 answer->AddContent(data_content->name, data_content->type, rejected,
2007 data_answer.release());
2008 return true;
2009}
2010
henrike@webrtc.org28e20752013-07-10 00:45:362011bool IsMediaContent(const ContentInfo* content) {
2012 return (content &&
2013 (content->type == NS_JINGLE_RTP ||
2014 content->type == NS_JINGLE_DRAFT_SCTP));
2015}
2016
2017bool IsAudioContent(const ContentInfo* content) {
2018 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2019}
2020
2021bool IsVideoContent(const ContentInfo* content) {
2022 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2023}
2024
2025bool IsDataContent(const ContentInfo* content) {
2026 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2027}
2028
deadbeef0ed85b22016-02-24 01:24:522029const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2030 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 15:14:502031 for (const ContentInfo& content : contents) {
2032 if (IsMediaContentOfType(&content, media_type)) {
2033 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:362034 }
2035 }
deadbeef0ed85b22016-02-24 01:24:522036 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:362037}
2038
2039const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2040 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2041}
2042
2043const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2044 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2045}
2046
2047const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2048 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2049}
2050
2051static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2052 MediaType media_type) {
deadbeef0ed85b22016-02-24 01:24:522053 if (sdesc == nullptr) {
2054 return nullptr;
2055 }
henrike@webrtc.org28e20752013-07-10 00:45:362056
2057 return GetFirstMediaContent(sdesc->contents(), media_type);
2058}
2059
2060const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2061 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2062}
2063
2064const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2065 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2066}
2067
2068const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2069 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2070}
2071
2072const MediaContentDescription* GetFirstMediaContentDescription(
2073 const SessionDescription* sdesc, MediaType media_type) {
2074 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2075 const ContentDescription* description = content ? content->description : NULL;
2076 return static_cast<const MediaContentDescription*>(description);
2077}
2078
2079const AudioContentDescription* GetFirstAudioContentDescription(
2080 const SessionDescription* sdesc) {
2081 return static_cast<const AudioContentDescription*>(
2082 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2083}
2084
2085const VideoContentDescription* GetFirstVideoContentDescription(
2086 const SessionDescription* sdesc) {
2087 return static_cast<const VideoContentDescription*>(
2088 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2089}
2090
2091const DataContentDescription* GetFirstDataContentDescription(
2092 const SessionDescription* sdesc) {
2093 return static_cast<const DataContentDescription*>(
2094 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2095}
2096
Taylor Brandstetterdc4eb8c2016-05-12 15:14:502097//
2098// Non-const versions of the above functions.
2099//
2100
2101ContentInfo* GetFirstMediaContent(ContentInfos& contents,
2102 MediaType media_type) {
2103 for (ContentInfo& content : contents) {
2104 if (IsMediaContentOfType(&content, media_type)) {
2105 return &content;
2106 }
2107 }
2108 return nullptr;
2109}
2110
2111ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
2112 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2113}
2114
2115ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
2116 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2117}
2118
2119ContentInfo* GetFirstDataContent(ContentInfos& contents) {
2120 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2121}
2122
2123static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2124 MediaType media_type) {
2125 if (sdesc == nullptr) {
2126 return nullptr;
2127 }
2128
2129 return GetFirstMediaContent(sdesc->contents(), media_type);
2130}
2131
2132ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2133 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2134}
2135
2136ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2137 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2138}
2139
2140ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2141 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2142}
2143
2144MediaContentDescription* GetFirstMediaContentDescription(
2145 SessionDescription* sdesc,
2146 MediaType media_type) {
2147 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2148 ContentDescription* description = content ? content->description : NULL;
2149 return static_cast<MediaContentDescription*>(description);
2150}
2151
2152AudioContentDescription* GetFirstAudioContentDescription(
2153 SessionDescription* sdesc) {
2154 return static_cast<AudioContentDescription*>(
2155 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2156}
2157
2158VideoContentDescription* GetFirstVideoContentDescription(
2159 SessionDescription* sdesc) {
2160 return static_cast<VideoContentDescription*>(
2161 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2162}
2163
2164DataContentDescription* GetFirstDataContentDescription(
2165 SessionDescription* sdesc) {
2166 return static_cast<DataContentDescription*>(
2167 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2168}
2169
henrike@webrtc.org28e20752013-07-10 00:45:362170} // namespace cricket