blob: 87222bec31a59c4ec31ea2f80125ca2eea27fe29 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeef67cf2c12016-04-13 10:07:16 -070013#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "api/optional.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020022#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "media/base/cryptoparams.h"
24#include "media/base/h264_profile_level_id.h"
25#include "media/base/mediaconstants.h"
26#include "p2p/base/p2pconstants.h"
27#include "pc/channelmanager.h"
28#include "pc/srtpfilter.h"
29#include "rtc_base/base64.h"
30#include "rtc_base/checks.h"
31#include "rtc_base/helpers.h"
32#include "rtc_base/logging.h"
33#include "rtc_base/stringutils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
35namespace {
36const char kInline[] = "inline:";
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080037
deadbeef7914b8c2017-04-21 03:23:33 -070038void GetSupportedSdesCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
39 std::vector<int>*),
40 const rtc::CryptoOptions& crypto_options,
41 std::vector<std::string>* names) {
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080042 std::vector<int> crypto_suites;
jbauchcb560652016-08-04 05:20:32 -070043 func(crypto_options, &crypto_suites);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080044 for (const auto crypto : crypto_suites) {
45 names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
46 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -080047}
terelius8c011e52016-04-26 05:28:11 -070048} // namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
50namespace cricket {
51
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052// RTP Profile names
53// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
54// RFC4585
55const char kMediaProtocolAvpf[] = "RTP/AVPF";
56// RFC5124
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +000057const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
58
deadbeeff3938292015-07-15 12:20:53 -070059// We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
60// but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061const char kMediaProtocolSavpf[] = "RTP/SAVPF";
62
63const char kMediaProtocolRtpPrefix[] = "RTP/";
64
65const char kMediaProtocolSctp[] = "SCTP";
66const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
lally@webrtc.orgec97c652015-02-24 20:18:48 +000067const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
lally@webrtc.orga7470932015-02-24 20:19:21 +000068const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069
deadbeef8b7e9ad2017-05-25 09:38:55 -070070// Note that the below functions support some protocol strings purely for
71// legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
72// and Interoperability.
73
74static bool IsDtlsRtp(const std::string& protocol) {
75 // Most-likely values first.
76 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" ||
77 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP";
78}
79
80static bool IsPlainRtp(const std::string& protocol) {
81 // Most-likely values first.
82 return protocol == "RTP/SAVPF" || protocol == "RTP/AVPF" ||
83 protocol == "RTP/SAVP" || protocol == "RTP/AVP";
84}
85
86static bool IsDtlsSctp(const std::string& protocol) {
87 return protocol == kMediaProtocolDtlsSctp ||
88 protocol == kMediaProtocolUdpDtlsSctp ||
89 protocol == kMediaProtocolTcpDtlsSctp;
90}
91
92static bool IsPlainSctp(const std::string& protocol) {
93 return protocol == kMediaProtocolSctp;
94}
95
96static bool IsSctp(const std::string& protocol) {
97 return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
98}
99
ossu075af922016-06-14 03:29:38 -0700100RtpTransceiverDirection RtpTransceiverDirection::FromMediaContentDirection(
101 MediaContentDirection md) {
102 const bool send = (md == MD_SENDRECV || md == MD_SENDONLY);
103 const bool recv = (md == MD_SENDRECV || md == MD_RECVONLY);
104 return RtpTransceiverDirection(send, recv);
105}
106
107MediaContentDirection RtpTransceiverDirection::ToMediaContentDirection() const {
108 if (send && recv) {
109 return MD_SENDRECV;
110 } else if (send) {
111 return MD_SENDONLY;
112 } else if (recv) {
113 return MD_RECVONLY;
114 }
115
116 return MD_INACTIVE;
117}
118
119RtpTransceiverDirection
120NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
121 RtpTransceiverDirection wants) {
122 return RtpTransceiverDirection(offer.recv && wants.send,
123 offer.send && wants.recv);
124}
125
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126static bool IsMediaContentOfType(const ContentInfo* content,
127 MediaType media_type) {
128 if (!IsMediaContent(content)) {
129 return false;
130 }
131
132 const MediaContentDescription* mdesc =
133 static_cast<const MediaContentDescription*>(content->description);
134 return mdesc && mdesc->type() == media_type;
135}
136
137static bool CreateCryptoParams(int tag, const std::string& cipher,
138 CryptoParams *out) {
jbauchcb560652016-08-04 05:20:32 -0700139 int key_len;
140 int salt_len;
141 if (!rtc::GetSrtpKeyAndSaltLengths(
142 rtc::SrtpCryptoSuiteFromName(cipher), &key_len, &salt_len)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143 return false;
144 }
jbauchcb560652016-08-04 05:20:32 -0700145
146 int master_key_len = key_len + salt_len;
147 std::string master_key;
148 if (!rtc::CreateRandomData(master_key_len, &master_key)) {
149 return false;
150 }
151
kwiberg352444f2016-11-28 15:58:53 -0800152 RTC_CHECK_EQ(master_key_len, master_key.size());
jbauchcb560652016-08-04 05:20:32 -0700153 std::string key = rtc::Base64::Encode(master_key);
154
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 out->tag = tag;
156 out->cipher_suite = cipher;
157 out->key_params = kInline;
158 out->key_params += key;
159 return true;
160}
161
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162static bool AddCryptoParams(const std::string& cipher_suite,
163 CryptoParamsVec *out) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000164 int size = static_cast<int>(out->size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165
166 out->resize(size + 1);
167 return CreateCryptoParams(size, cipher_suite, &out->at(size));
168}
169
170void AddMediaCryptos(const CryptoParamsVec& cryptos,
171 MediaContentDescription* media) {
172 for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
173 crypto != cryptos.end(); ++crypto) {
174 media->AddCrypto(*crypto);
175 }
176}
177
178bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
179 MediaContentDescription* media) {
180 CryptoParamsVec cryptos;
181 for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
182 it != crypto_suites.end(); ++it) {
183 if (!AddCryptoParams(*it, &cryptos)) {
184 return false;
185 }
186 }
187 AddMediaCryptos(cryptos, media);
188 return true;
189}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190
zhihuang1c378ed2017-08-17 14:10:50 -0700191const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
192 if (!content) {
193 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000194 }
zhihuang1c378ed2017-08-17 14:10:50 -0700195
196 RTC_DCHECK(IsMediaContent(content));
197 return &(static_cast<const MediaContentDescription*>(content->description)
198 ->cryptos());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199}
200
201bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
202 const CryptoParams& crypto,
203 CryptoParams* out) {
204 for (CryptoParamsVec::const_iterator it = cryptos.begin();
205 it != cryptos.end(); ++it) {
206 if (crypto.Matches(*it)) {
207 *out = *it;
208 return true;
209 }
210 }
211 return false;
212}
213
jbauchcb560652016-08-04 05:20:32 -0700214// For audio, HMAC 32 is prefered over HMAC 80 because of the low overhead.
deadbeef7914b8c2017-04-21 03:23:33 -0700215void GetSupportedAudioSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
216 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700217 if (crypto_options.enable_gcm_crypto_suites) {
218 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
219 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
220 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800221 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
222 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223}
224
deadbeef7914b8c2017-04-21 03:23:33 -0700225void GetSupportedAudioSdesCryptoSuiteNames(
226 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800227 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700228 GetSupportedSdesCryptoSuiteNames(GetSupportedAudioSdesCryptoSuites,
229 crypto_options, crypto_suite_names);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230}
231
deadbeef7914b8c2017-04-21 03:23:33 -0700232void GetSupportedVideoSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
233 std::vector<int>* crypto_suites) {
jbauchcb560652016-08-04 05:20:32 -0700234 if (crypto_options.enable_gcm_crypto_suites) {
235 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
236 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
237 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800238 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000239}
240
deadbeef7914b8c2017-04-21 03:23:33 -0700241void GetSupportedVideoSdesCryptoSuiteNames(
242 const rtc::CryptoOptions& crypto_options,
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800243 std::vector<std::string>* crypto_suite_names) {
deadbeef7914b8c2017-04-21 03:23:33 -0700244 GetSupportedSdesCryptoSuiteNames(GetSupportedVideoSdesCryptoSuites,
245 crypto_options, crypto_suite_names);
246}
247
248void GetSupportedDataSdesCryptoSuites(const rtc::CryptoOptions& crypto_options,
249 std::vector<int>* crypto_suites) {
250 if (crypto_options.enable_gcm_crypto_suites) {
251 crypto_suites->push_back(rtc::SRTP_AEAD_AES_256_GCM);
252 crypto_suites->push_back(rtc::SRTP_AEAD_AES_128_GCM);
253 }
254 crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
255}
256
257void GetSupportedDataSdesCryptoSuiteNames(
258 const rtc::CryptoOptions& crypto_options,
259 std::vector<std::string>* crypto_suite_names) {
260 GetSupportedSdesCryptoSuiteNames(GetSupportedDataSdesCryptoSuites,
261 crypto_options, crypto_suite_names);
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -0800262}
263
jbauchcb560652016-08-04 05:20:32 -0700264// Support any GCM cipher (if enabled through options). For video support only
265// 80-bit SHA1 HMAC. For audio 32-bit HMAC is tolerated unless bundle is enabled
266// because it is low overhead.
267// Pick the crypto in the list that is supported.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268static bool SelectCrypto(const MediaContentDescription* offer,
269 bool bundle,
jbauchcb560652016-08-04 05:20:32 -0700270 const rtc::CryptoOptions& crypto_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 CryptoParams *crypto) {
272 bool audio = offer->type() == MEDIA_TYPE_AUDIO;
273 const CryptoParamsVec& cryptos = offer->cryptos();
274
275 for (CryptoParamsVec::const_iterator i = cryptos.begin();
276 i != cryptos.end(); ++i) {
jbauchcb560652016-08-04 05:20:32 -0700277 if ((crypto_options.enable_gcm_crypto_suites &&
278 rtc::IsGcmCryptoSuiteName(i->cipher_suite)) ||
279 rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
Guo-wei Shieh456696a2015-09-30 21:48:54 -0700280 (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
281 !bundle)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000282 return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
283 }
284 }
285 return false;
286}
287
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288// Generate random SSRC values that are not already present in |params_vec|.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000289// The generated values are added to |ssrcs|.
290// |num_ssrcs| is the number of the SSRC will be generated.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291static void GenerateSsrcs(const StreamParamsVec& params_vec,
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000292 int num_ssrcs,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200293 std::vector<uint32_t>* ssrcs) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000294 for (int i = 0; i < num_ssrcs; i++) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200295 uint32_t candidate;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 do {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000297 candidate = rtc::CreateRandomNonZeroId();
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000298 } while (GetStreamBySsrc(params_vec, candidate) ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
300 ssrcs->push_back(candidate);
301 }
302}
303
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304// Finds all StreamParams of all media types and attach them to stream_params.
305static void GetCurrentStreamParams(const SessionDescription* sdesc,
306 StreamParamsVec* stream_params) {
307 if (!sdesc)
308 return;
309
310 const ContentInfos& contents = sdesc->contents();
311 for (ContentInfos::const_iterator content = contents.begin();
312 content != contents.end(); ++content) {
313 if (!IsMediaContent(&*content)) {
314 continue;
315 }
316 const MediaContentDescription* media =
317 static_cast<const MediaContentDescription*>(
318 content->description);
319 const StreamParamsVec& streams = media->streams();
320 for (StreamParamsVec::const_iterator it = streams.begin();
321 it != streams.end(); ++it) {
322 stream_params->push_back(*it);
323 }
324 }
325}
326
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000327// Filters the data codecs for the data channel type.
328void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
329 // Filter RTP codec for SCTP and vice versa.
solenberg9fa49752016-10-08 13:02:44 -0700330 const char* codec_name =
331 sctp ? kGoogleRtpDataCodecName : kGoogleSctpDataCodecName;
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000332 for (std::vector<DataCodec>::iterator iter = codecs->begin();
333 iter != codecs->end();) {
solenberg9fa49752016-10-08 13:02:44 -0700334 if (CodecNamesEq(iter->name, codec_name)) {
jiayl@webrtc.org9c16c392014-05-01 18:30:30 +0000335 iter = codecs->erase(iter);
336 } else {
337 ++iter;
338 }
339 }
340}
341
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342template <typename IdStruct>
343class UsedIds {
344 public:
345 UsedIds(int min_allowed_id, int max_allowed_id)
346 : min_allowed_id_(min_allowed_id),
347 max_allowed_id_(max_allowed_id),
348 next_id_(max_allowed_id) {
349 }
350
351 // Loops through all Id in |ids| and changes its id if it is
352 // already in use by another IdStruct. Call this methods with all Id
353 // in a session description to make sure no duplicate ids exists.
354 // Note that typename Id must be a type of IdStruct.
355 template <typename Id>
356 void FindAndSetIdUsed(std::vector<Id>* ids) {
357 for (typename std::vector<Id>::iterator it = ids->begin();
358 it != ids->end(); ++it) {
359 FindAndSetIdUsed(&*it);
360 }
361 }
362
363 // Finds and sets an unused id if the |idstruct| id is already in use.
364 void FindAndSetIdUsed(IdStruct* idstruct) {
365 const int original_id = idstruct->id;
366 int new_id = idstruct->id;
367
368 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
369 // If the original id is not in range - this is an id that can't be
370 // dynamically changed.
371 return;
372 }
373
374 if (IsIdUsed(original_id)) {
375 new_id = FindUnusedId();
376 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
377 << " to " << new_id;
378 idstruct->id = new_id;
379 }
380 SetIdUsed(new_id);
381 }
382
383 private:
384 // Returns the first unused id in reverse order.
385 // This hopefully reduce the risk of more collisions. We want to change the
386 // default ids as little as possible.
387 int FindUnusedId() {
388 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
389 --next_id_;
390 }
nisseede5da42017-01-12 05:15:36 -0800391 RTC_DCHECK(next_id_ >= min_allowed_id_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000392 return next_id_;
393 }
394
395 bool IsIdUsed(int new_id) {
396 return id_set_.find(new_id) != id_set_.end();
397 }
398
399 void SetIdUsed(int new_id) {
400 id_set_.insert(new_id);
401 }
402
403 const int min_allowed_id_;
404 const int max_allowed_id_;
405 int next_id_;
406 std::set<int> id_set_;
407};
408
409// Helper class used for finding duplicate RTP payload types among audio, video
410// and data codecs. When bundle is used the payload types may not collide.
411class UsedPayloadTypes : public UsedIds<Codec> {
412 public:
413 UsedPayloadTypes()
414 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
415 }
416
417
418 private:
419 static const int kDynamicPayloadTypeMin = 96;
420 static const int kDynamicPayloadTypeMax = 127;
421};
422
423// Helper class used for finding duplicate RTP Header extension ids among
424// audio and video extensions.
isheriff6f8d6862016-05-26 11:24:55 -0700425class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 public:
427 UsedRtpHeaderExtensionIds()
deadbeefe814a0d2017-02-25 18:15:09 -0800428 : UsedIds<webrtc::RtpExtension>(webrtc::RtpExtension::kMinId,
429 webrtc::RtpExtension::kMaxId) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430
431 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432};
433
zhihuang1c378ed2017-08-17 14:10:50 -0700434// Adds a StreamParams for each SenderOptions in |sender_options| to
435// content_description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436// |current_params| - All currently known StreamParams of any media type.
437template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700438static bool AddStreamParams(
439 const std::vector<SenderOptions>& sender_options,
440 const std::string& rtcp_cname,
441 StreamParamsVec* current_streams,
442 MediaContentDescriptionImpl<C>* content_description) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700443 // SCTP streams are not negotiated using SDP/ContentDescriptions.
deadbeef8b7e9ad2017-05-25 09:38:55 -0700444 if (IsSctp(content_description->protocol())) {
Taylor Brandstetter1d7a6372016-08-24 13:15:27 -0700445 return true;
446 }
447
Noah Richards2e7a0982015-05-18 14:02:54 -0700448 const bool include_rtx_streams =
449 ContainsRtxCodec(content_description->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000451
brandtr03d5fb12016-11-22 03:37:59 -0800452 const bool include_flexfec_stream =
453 ContainsFlexfecCodec(content_description->codecs());
454
zhihuang1c378ed2017-08-17 14:10:50 -0700455 for (const SenderOptions& sender : sender_options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 // groupid is empty for StreamParams generated using
457 // MediaSessionDescriptionFactory.
zhihuang1c378ed2017-08-17 14:10:50 -0700458 StreamParams* param =
459 GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000460 if (!param) {
zhihuang1c378ed2017-08-17 14:10:50 -0700461 // This is a new sender.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200462 std::vector<uint32_t> ssrcs;
zhihuang1c378ed2017-08-17 14:10:50 -0700463 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 StreamParams stream_param;
zhihuang1c378ed2017-08-17 14:10:50 -0700465 stream_param.id = sender.track_id;
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000466 // Add the generated ssrc.
467 for (size_t i = 0; i < ssrcs.size(); ++i) {
468 stream_param.ssrcs.push_back(ssrcs[i]);
469 }
zhihuang1c378ed2017-08-17 14:10:50 -0700470 if (sender.num_sim_layers > 1) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000471 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
472 stream_param.ssrc_groups.push_back(group);
473 }
Noah Richards2e7a0982015-05-18 14:02:54 -0700474 // Generate extra ssrcs for include_rtx_streams case.
475 if (include_rtx_streams) {
476 // Generate an RTX ssrc for every ssrc in the group.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200477 std::vector<uint32_t> rtx_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -0700478 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
479 &rtx_ssrcs);
480 for (size_t i = 0; i < ssrcs.size(); ++i) {
481 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
482 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 content_description->set_multistream(true);
484 }
brandtr03d5fb12016-11-22 03:37:59 -0800485 // Generate extra ssrc for include_flexfec_stream case.
486 if (include_flexfec_stream) {
487 // TODO(brandtr): Update when we support multistream protection.
488 if (ssrcs.size() == 1) {
489 std::vector<uint32_t> flexfec_ssrcs;
490 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs);
491 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]);
492 content_description->set_multistream(true);
493 } else if (!ssrcs.empty()) {
494 LOG(LS_WARNING)
495 << "Our FlexFEC implementation only supports protecting "
496 << "a single media streams. This session has multiple "
497 << "media streams however, so no FlexFEC SSRC will be generated.";
498 }
499 }
zhihuang1c378ed2017-08-17 14:10:50 -0700500 stream_param.cname = rtcp_cname;
Steve Anton8ffb9c32017-08-31 15:45:38 -0700501 // TODO(steveanton): Support any number of stream ids.
502 RTC_CHECK(sender.stream_ids.size() == 1U);
503 stream_param.sync_label = sender.stream_ids[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 content_description->AddStream(stream_param);
505
506 // Store the new StreamParams in current_streams.
507 // This is necessary so that we can use the CNAME for other media types.
508 current_streams->push_back(stream_param);
509 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700510 // Use existing generated SSRCs/groups, but update the sync_label if
511 // necessary. This may be needed if a MediaStreamTrack was moved from one
512 // MediaStream to another.
Steve Anton8ffb9c32017-08-31 15:45:38 -0700513 // TODO(steveanton): Support any number of stream ids.
514 RTC_CHECK(sender.stream_ids.size() == 1U);
515 param->sync_label = sender.stream_ids[0];
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000516 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 }
518 }
519 return true;
520}
521
522// Updates the transport infos of the |sdesc| according to the given
523// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800524// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
525// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
527 SessionDescription* sdesc) {
528 // The bundle should not be empty.
529 if (!sdesc || !bundle_group.FirstContentName()) {
530 return false;
531 }
532
533 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700534 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 const TransportInfo* selected_transport_info =
536 sdesc->GetTransportInfoByName(selected_content_name);
537 if (!selected_transport_info) {
538 return false;
539 }
540
541 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700542 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700544 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800546 ConnectionRole selected_connection_role =
547 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 for (TransportInfos::iterator it =
549 sdesc->transport_infos().begin();
550 it != sdesc->transport_infos().end(); ++it) {
551 if (bundle_group.HasContentName(it->content_name) &&
552 it->content_name != selected_content_name) {
553 it->description.ice_ufrag = selected_ufrag;
554 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800555 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 }
557 }
558 return true;
559}
560
561// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
562// sets it to |cryptos|.
563static bool GetCryptosByName(const SessionDescription* sdesc,
564 const std::string& content_name,
565 CryptoParamsVec* cryptos) {
566 if (!sdesc || !cryptos) {
567 return false;
568 }
569
570 const ContentInfo* content = sdesc->GetContentByName(content_name);
571 if (!IsMediaContent(content) || !content->description) {
572 return false;
573 }
574
575 const MediaContentDescription* media_desc =
576 static_cast<const MediaContentDescription*>(content->description);
577 *cryptos = media_desc->cryptos();
578 return true;
579}
580
581// Predicate function used by the remove_if.
582// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
583static bool CryptoNotFound(const CryptoParams crypto,
584 const CryptoParamsVec* filter) {
585 if (filter == NULL) {
586 return true;
587 }
588 for (CryptoParamsVec::const_iterator it = filter->begin();
589 it != filter->end(); ++it) {
590 if (it->cipher_suite == crypto.cipher_suite) {
591 return false;
592 }
593 }
594 return true;
595}
596
597// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
598// which are not available in |filter|.
599static void PruneCryptos(const CryptoParamsVec& filter,
600 CryptoParamsVec* target_cryptos) {
601 if (!target_cryptos) {
602 return;
603 }
604 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
605 target_cryptos->end(),
606 bind2nd(ptr_fun(CryptoNotFound),
607 &filter)),
608 target_cryptos->end());
609}
610
deadbeefb5cb19b2015-11-23 16:39:12 -0800611static bool IsRtpProtocol(const std::string& protocol) {
612 return protocol.empty() ||
613 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
614}
615
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616static bool IsRtpContent(SessionDescription* sdesc,
617 const std::string& content_name) {
618 bool is_rtp = false;
619 ContentInfo* content = sdesc->GetContentByName(content_name);
620 if (IsMediaContent(content)) {
621 MediaContentDescription* media_desc =
622 static_cast<MediaContentDescription*>(content->description);
623 if (!media_desc) {
624 return false;
625 }
deadbeefb5cb19b2015-11-23 16:39:12 -0800626 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 }
628 return is_rtp;
629}
630
631// Updates the crypto parameters of the |sdesc| according to the given
632// |bundle_group|. The crypto parameters of all the contents within the
633// |bundle_group| should be updated to use the common subset of the
634// available cryptos.
635static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
636 SessionDescription* sdesc) {
637 // The bundle should not be empty.
638 if (!sdesc || !bundle_group.FirstContentName()) {
639 return false;
640 }
641
wu@webrtc.org78187522013-10-07 23:32:02 +0000642 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 // Get the common cryptos.
644 const ContentNames& content_names = bundle_group.content_names();
645 CryptoParamsVec common_cryptos;
646 for (ContentNames::const_iterator it = content_names.begin();
647 it != content_names.end(); ++it) {
648 if (!IsRtpContent(sdesc, *it)) {
649 continue;
650 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000651 // The common cryptos are needed if any of the content does not have DTLS
652 // enabled.
653 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
654 common_cryptos_needed = true;
655 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 if (it == content_names.begin()) {
657 // Initial the common_cryptos with the first content in the bundle group.
658 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
659 return false;
660 }
661 if (common_cryptos.empty()) {
662 // If there's no crypto params, we should just return.
663 return true;
664 }
665 } else {
666 CryptoParamsVec cryptos;
667 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
668 return false;
669 }
670 PruneCryptos(cryptos, &common_cryptos);
671 }
672 }
673
wu@webrtc.org78187522013-10-07 23:32:02 +0000674 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 return false;
676 }
677
678 // Update to use the common cryptos.
679 for (ContentNames::const_iterator it = content_names.begin();
680 it != content_names.end(); ++it) {
681 if (!IsRtpContent(sdesc, *it)) {
682 continue;
683 }
684 ContentInfo* content = sdesc->GetContentByName(*it);
685 if (IsMediaContent(content)) {
686 MediaContentDescription* media_desc =
687 static_cast<MediaContentDescription*>(content->description);
688 if (!media_desc) {
689 return false;
690 }
691 media_desc->set_cryptos(common_cryptos);
692 }
693 }
694 return true;
695}
696
697template <class C>
698static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800699 for (const auto& codec : codecs) {
700 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 return true;
702 }
703 }
704 return false;
705}
706
707template <class C>
708static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800709 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710}
711
brandtr03d5fb12016-11-22 03:37:59 -0800712template <class C>
713static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
714 for (const auto& codec : codecs) {
715 if (IsFlexfecCodec(codec)) {
716 return true;
717 }
718 }
719 return false;
720}
721
722template <class C>
723static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800724 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800725}
726
zhihuang1c378ed2017-08-17 14:10:50 -0700727// Create a media content to be offered for the given |sender_options|,
728// according to the given options.rtcp_mux, session_options.is_muc, codecs,
729// secure_transport, crypto, and current_streams. If we don't currently have
730// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
731// created (according to crypto_suites). The created content is added to the
732// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733template <class C>
734static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700735 const std::vector<SenderOptions>& sender_options,
736 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000738 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 const CryptoParamsVec* current_cryptos,
740 const std::vector<std::string>& crypto_suites,
741 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 StreamParamsVec* current_streams,
743 MediaContentDescriptionImpl<C>* offer) {
744 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745
zhihuang1c378ed2017-08-17 14:10:50 -0700746 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700747 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
748 offer->set_rtcp_reduced_size(true);
749 }
zhihuang1c378ed2017-08-17 14:10:50 -0700750 offer->set_multistream(session_options.is_muc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751 offer->set_rtp_header_extensions(rtp_extensions);
752
zhihuang1c378ed2017-08-17 14:10:50 -0700753 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
754 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755 return false;
756 }
757
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758 if (secure_policy != SEC_DISABLED) {
759 if (current_cryptos) {
760 AddMediaCryptos(*current_cryptos, offer);
761 }
762 if (offer->cryptos().empty()) {
763 if (!CreateMediaCryptos(crypto_suites, offer)) {
764 return false;
765 }
766 }
767 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
deadbeef7af91dd2016-12-13 11:29:11 -0800769 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 return false;
771 }
772 return true;
773}
774
775template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000776static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800777 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000778 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800779 const int codec2_id) {
780 const C* codec1 = FindCodecById(codecs1, codec1_id);
781 const C* codec2 = FindCodecById(codecs2, codec2_id);
782 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000783}
784
785template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786static void NegotiateCodecs(const std::vector<C>& local_codecs,
787 const std::vector<C>& offered_codecs,
788 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800789 for (const C& ours : local_codecs) {
790 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700791 // Note that we intentionally only find one matching codec for each of our
792 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800793 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
794 C negotiated = ours;
795 negotiated.IntersectFeedbackParams(theirs);
796 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800797 const auto apt_it =
798 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800799 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800800 RTC_DCHECK(apt_it != theirs.params.end());
801 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 }
magjedf823ede2016-11-12 09:53:04 -0800803 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
804 webrtc::H264::GenerateProfileLevelIdForAnswer(
805 ours.params, theirs.params, &negotiated.params);
806 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800807 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700808 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800809 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 }
811 }
deadbeef67cf2c12016-04-13 10:07:16 -0700812 // RFC3264: Although the answerer MAY list the formats in their desired
813 // order of preference, it is RECOMMENDED that unless there is a
814 // specific reason, the answerer list formats in the same relative order
815 // they were present in the offer.
816 std::unordered_map<int, int> payload_type_preferences;
817 int preference = static_cast<int>(offered_codecs.size() + 1);
818 for (const C& codec : offered_codecs) {
819 payload_type_preferences[codec.id] = preference--;
820 }
821 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
822 [&payload_type_preferences](const C& a, const C& b) {
823 return payload_type_preferences[a.id] >
824 payload_type_preferences[b.id];
825 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826}
827
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800828// Finds a codec in |codecs2| that matches |codec_to_match|, which is
829// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
830// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800832static bool FindMatchingCodec(const std::vector<C>& codecs1,
833 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 const C& codec_to_match,
835 C* found_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800836 for (const C& potential_match : codecs2) {
837 if (potential_match.Matches(codec_to_match)) {
838 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800839 int apt_value_1 = 0;
840 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800841 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
842 &apt_value_1) ||
843 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
844 &apt_value_2)) {
845 LOG(LS_WARNING) << "RTX missing associated payload type.";
846 continue;
847 }
848 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
849 apt_value_2)) {
850 continue;
851 }
852 }
853 if (found_codec) {
854 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 }
856 return true;
857 }
858 }
859 return false;
860}
861
zhihuang1c378ed2017-08-17 14:10:50 -0700862// Find the codec in |codec_list| that |rtx_codec| is associated with.
863template <class C>
864static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
865 const C& rtx_codec) {
866 std::string associated_pt_str;
867 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
868 &associated_pt_str)) {
869 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
870 << " is missing an associated payload type.";
871 return nullptr;
872 }
873
874 int associated_pt;
875 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
876 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
877 << " of RTX codec " << rtx_codec.name << " to an integer.";
878 return nullptr;
879 }
880
881 // Find the associated reference codec for the reference RTX codec.
882 const C* associated_codec = FindCodecById(codec_list, associated_pt);
883 if (!associated_codec) {
884 LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
885 << associated_pt << " for RTX codec " << rtx_codec.name
886 << ".";
887 }
888 return associated_codec;
889}
890
891// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892// already exist in |offered_codecs| and ensure the payload types don't
893// collide.
894template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700895static void MergeCodecs(const std::vector<C>& reference_codecs,
896 std::vector<C>* offered_codecs,
897 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800899 for (const C& reference_codec : reference_codecs) {
900 if (!IsRtxCodec(reference_codec) &&
901 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
902 reference_codec, nullptr)) {
903 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 used_pltypes->FindAndSetIdUsed(&codec);
905 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000906 }
907 }
908
909 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800910 for (const C& reference_codec : reference_codecs) {
911 if (IsRtxCodec(reference_codec) &&
912 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
913 reference_codec, nullptr)) {
914 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700915 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700916 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700917 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700918 continue;
919 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800920 // Find a codec in the offered list that matches the reference codec.
921 // Its payload type may be different than the reference codec.
922 C matching_codec;
923 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800924 *associated_codec, &matching_codec)) {
925 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800926 << " codec.";
927 continue;
928 }
929
930 rtx_codec.params[kCodecParamAssociatedPayloadType] =
931 rtc::ToString(matching_codec.id);
932 used_pltypes->FindAndSetIdUsed(&rtx_codec);
933 offered_codecs->push_back(rtx_codec);
934 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 }
936}
937
zhihuang1c378ed2017-08-17 14:10:50 -0700938static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
939 const webrtc::RtpExtension& ext_to_match,
940 webrtc::RtpExtension* found_extension) {
941 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
942 it != extensions.end(); ++it) {
943 // We assume that all URIs are given in a canonical format.
944 if (it->uri == ext_to_match.uri && it->encrypt == ext_to_match.encrypt) {
945 if (found_extension) {
946 *found_extension = *it;
947 }
948 return true;
949 }
950 }
951 return false;
952}
953
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000954static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700955 const webrtc::RtpExtension& ext_to_match,
956 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700957 // We assume that all URIs are given in a canonical format.
958 const webrtc::RtpExtension* found =
959 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
960 ext_to_match.uri);
961 if (!found) {
962 return false;
963 }
964 if (found_extension) {
965 *found_extension = *found;
966 }
967 return true;
968}
969
970static bool FindByUriWithEncryptionPreference(
971 const RtpHeaderExtensions& extensions,
972 const webrtc::RtpExtension& ext_to_match, bool encryption_preference,
973 webrtc::RtpExtension* found_extension) {
974 const webrtc::RtpExtension* unencrypted_extension = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
976 it != extensions.end(); ++it) {
977 // We assume that all URIs are given in a canonical format.
978 if (it->uri == ext_to_match.uri) {
jbauch5869f502017-06-29 12:31:36 -0700979 if (!encryption_preference || it->encrypt) {
980 if (found_extension) {
981 *found_extension = *it;
982 }
983 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 }
jbauch5869f502017-06-29 12:31:36 -0700985 unencrypted_extension = &(*it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 }
987 }
jbauch5869f502017-06-29 12:31:36 -0700988 if (unencrypted_extension) {
989 if (found_extension) {
990 *found_extension = *unencrypted_extension;
991 }
992 return true;
993 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994 return false;
995}
996
zhihuang1c378ed2017-08-17 14:10:50 -0700997// Adds all extensions from |reference_extensions| to |offered_extensions| that
998// don't already exist in |offered_extensions| and ensure the IDs don't
999// collide. If an extension is added, it's also added to |regular_extensions| or
1000// |encrypted_extensions|, and if the extension is in |regular_extensions| or
1001// |encrypted_extensions|, its ID is marked as used in |used_ids|.
1002// |offered_extensions| is for either audio or video while |regular_extensions|
1003// and |encrypted_extensions| are used for both audio and video. There could be
1004// overlap between audio extensions and video extensions.
1005static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1006 RtpHeaderExtensions* offered_extensions,
1007 RtpHeaderExtensions* regular_extensions,
1008 RtpHeaderExtensions* encrypted_extensions,
1009 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001010 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001011 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1012 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001013 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001014 if (reference_extension.encrypt) {
1015 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1016 &existing)) {
1017 offered_extensions->push_back(existing);
1018 } else {
1019 used_ids->FindAndSetIdUsed(&reference_extension);
1020 encrypted_extensions->push_back(reference_extension);
1021 offered_extensions->push_back(reference_extension);
1022 }
olka3c747662017-08-17 06:50:32 -07001023 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001024 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1025 &existing)) {
1026 offered_extensions->push_back(existing);
1027 } else {
1028 used_ids->FindAndSetIdUsed(&reference_extension);
1029 regular_extensions->push_back(reference_extension);
1030 offered_extensions->push_back(reference_extension);
1031 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001032 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 }
1034 }
1035}
1036
jbauch5869f502017-06-29 12:31:36 -07001037static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1038 RtpHeaderExtensions* all_extensions,
1039 UsedRtpHeaderExtensionIds* used_ids) {
1040 RtpHeaderExtensions encrypted_extensions;
1041 for (const webrtc::RtpExtension& extension : *extensions) {
1042 webrtc::RtpExtension existing;
1043 // Don't add encrypted extensions again that were already included in a
1044 // previous offer or regular extensions that are also included as encrypted
1045 // extensions.
1046 if (extension.encrypt ||
1047 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1048 (FindByUriWithEncryptionPreference(*extensions, extension, true,
1049 &existing) && existing.encrypt)) {
1050 continue;
1051 }
1052
1053 if (FindByUri(*all_extensions, extension, &existing)) {
1054 encrypted_extensions.push_back(existing);
1055 } else {
1056 webrtc::RtpExtension encrypted(extension);
1057 encrypted.encrypt = true;
1058 used_ids->FindAndSetIdUsed(&encrypted);
1059 all_extensions->push_back(encrypted);
1060 encrypted_extensions.push_back(encrypted);
1061 }
1062 }
1063 extensions->insert(extensions->end(), encrypted_extensions.begin(),
1064 encrypted_extensions.end());
1065}
1066
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067static void NegotiateRtpHeaderExtensions(
1068 const RtpHeaderExtensions& local_extensions,
1069 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001070 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001071 RtpHeaderExtensions* negotiated_extenstions) {
1072 RtpHeaderExtensions::const_iterator ours;
1073 for (ours = local_extensions.begin();
1074 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 11:24:55 -07001075 webrtc::RtpExtension theirs;
jbauch5869f502017-06-29 12:31:36 -07001076 if (FindByUriWithEncryptionPreference(offered_extensions, *ours,
1077 enable_encrypted_rtp_header_extensions, &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078 // We respond with their RTP header extension id.
1079 negotiated_extenstions->push_back(theirs);
1080 }
1081 }
1082}
1083
1084static void StripCNCodecs(AudioCodecs* audio_codecs) {
1085 AudioCodecs::iterator iter = audio_codecs->begin();
1086 while (iter != audio_codecs->end()) {
nisse21e4e0b2017-02-20 05:01:01 -08001087 if (STR_CASE_CMP(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088 iter = audio_codecs->erase(iter);
1089 } else {
1090 ++iter;
1091 }
1092 }
1093}
1094
zhihuang1c378ed2017-08-17 14:10:50 -07001095// Create a media content to be answered for the given |sender_options|
1096// according to the given session_options.rtcp_mux, session_options.streams,
1097// codecs, crypto, and current_streams. If we don't currently have crypto (in
1098// current_cryptos) and it is enabled (in secure_policy), crypto is created
1099// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1100// negotiated with the offer. If the negotiation fails, this method returns
1101// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102template <class C>
1103static bool CreateMediaContentAnswer(
1104 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001105 const MediaDescriptionOptions& media_description_options,
1106 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001107 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001108 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109 const CryptoParamsVec* current_cryptos,
1110 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001111 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001112 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001113 bool bundle_enabled,
1114 MediaContentDescriptionImpl<C>* answer) {
1115 std::vector<C> negotiated_codecs;
1116 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1117 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118 answer->set_protocol(offer->protocol());
1119 RtpHeaderExtensions negotiated_rtp_extensions;
1120 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1121 offer->rtp_header_extensions(),
jbauch5869f502017-06-29 12:31:36 -07001122 enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123 &negotiated_rtp_extensions);
1124 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1125
zhihuang1c378ed2017-08-17 14:10:50 -07001126 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001127 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1128 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1129 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130
1131 if (sdes_policy != SEC_DISABLED) {
1132 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001133 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1134 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135 if (current_cryptos) {
1136 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1137 }
1138 answer->AddCrypto(crypto);
1139 }
1140 }
1141
deadbeef7af91dd2016-12-13 11:29:11 -08001142 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143 return false;
1144 }
1145
zhihuang1c378ed2017-08-17 14:10:50 -07001146 if (!AddStreamParams(media_description_options.sender_options,
1147 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148 return false; // Something went seriously wrong.
1149 }
1150
ossu075af922016-06-14 03:29:38 -07001151 auto offer_rtd =
1152 RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07001153
1154 answer->set_direction(NegotiateRtpTransceiverDirection(
1155 offer_rtd, media_description_options.direction)
1156 .ToMediaContentDirection());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001157 return true;
1158}
1159
1160static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001161 const std::string& protocol,
1162 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001163 // Since not all applications serialize and deserialize the media protocol,
1164 // we will have to accept |protocol| to be empty.
1165 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001166 return true;
1167 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001168
zhihuangcf5b37c2016-05-05 11:44:35 -07001169 if (type == MEDIA_TYPE_DATA) {
1170 // Check for SCTP, but also for RTP for RTP-based data channels.
1171 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1172 if (secure_transport) {
1173 // Most likely scenarios first.
1174 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1175 IsPlainRtp(protocol);
1176 } else {
1177 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1178 }
1179 }
1180
1181 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1182 // JSEP specifies.
1183 if (secure_transport) {
1184 // Most likely scenarios first.
1185 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1186 } else {
1187 return IsPlainRtp(protocol);
1188 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189}
1190
1191static void SetMediaProtocol(bool secure_transport,
1192 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001193 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001195 else if (secure_transport)
1196 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 else
1198 desc->set_protocol(kMediaProtocolAvpf);
1199}
1200
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001201// Gets the TransportInfo of the given |content_name| from the
1202// |current_description|. If doesn't exist, returns a new one.
1203static const TransportDescription* GetTransportDescription(
1204 const std::string& content_name,
1205 const SessionDescription* current_description) {
1206 const TransportDescription* desc = NULL;
1207 if (current_description) {
1208 const TransportInfo* info =
1209 current_description->GetTransportInfoByName(content_name);
1210 if (info) {
1211 desc = &info->description;
1212 }
1213 }
1214 return desc;
1215}
1216
1217// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001218static bool IsDtlsActive(const ContentInfo* content,
1219 const SessionDescription* current_description) {
1220 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001221 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001222 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001223
zhihuang1c378ed2017-08-17 14:10:50 -07001224 size_t msection_index = content - &current_description->contents()[0];
1225
1226 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001227 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001228 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001229
zhihuang1c378ed2017-08-17 14:10:50 -07001230 return current_description->transport_infos()[msection_index]
1231 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001232}
1233
ossu075af922016-06-14 03:29:38 -07001234std::string MediaContentDirectionToString(MediaContentDirection direction) {
1235 std::string dir_str;
1236 switch (direction) {
1237 case MD_INACTIVE:
1238 dir_str = "inactive";
1239 break;
1240 case MD_SENDONLY:
1241 dir_str = "sendonly";
1242 break;
1243 case MD_RECVONLY:
1244 dir_str = "recvonly";
1245 break;
1246 case MD_SENDRECV:
1247 dir_str = "sendrecv";
1248 break;
1249 default:
nissec80e7412017-01-11 05:56:46 -08001250 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07001251 break;
1252 }
1253
1254 return dir_str;
1255}
1256
Steve Anton8ffb9c32017-08-31 15:45:38 -07001257void MediaDescriptionOptions::AddAudioSender(
1258 const std::string& track_id,
1259 const std::vector<std::string>& stream_ids) {
zhihuang1c378ed2017-08-17 14:10:50 -07001260 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001261 AddSenderInternal(track_id, stream_ids, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001262}
1263
Steve Anton8ffb9c32017-08-31 15:45:38 -07001264void MediaDescriptionOptions::AddVideoSender(
1265 const std::string& track_id,
1266 const std::vector<std::string>& stream_ids,
1267 int num_sim_layers) {
zhihuang1c378ed2017-08-17 14:10:50 -07001268 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001269 AddSenderInternal(track_id, stream_ids, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001270}
1271
zhihuang1c378ed2017-08-17 14:10:50 -07001272void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1273 const std::string& stream_id) {
1274 RTC_DCHECK(type == MEDIA_TYPE_DATA);
Steve Anton8ffb9c32017-08-31 15:45:38 -07001275 // TODO(steveanton): Is it the case that RtpDataChannel will never have more
1276 // than one stream?
1277 AddSenderInternal(track_id, {stream_id}, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278}
1279
Steve Anton8ffb9c32017-08-31 15:45:38 -07001280void MediaDescriptionOptions::AddSenderInternal(
1281 const std::string& track_id,
1282 const std::vector<std::string>& stream_ids,
1283 int num_sim_layers) {
1284 // TODO(steveanton): Support any number of stream ids.
1285 RTC_CHECK(stream_ids.size() == 1U);
1286 sender_options.push_back(SenderOptions{track_id, stream_ids, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287}
1288
zhihuang1c378ed2017-08-17 14:10:50 -07001289bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1290 return std::find_if(media_description_options.begin(),
1291 media_description_options.end(),
1292 [type](const MediaDescriptionOptions& t) {
1293 return t.type == type;
1294 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001295}
1296
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1298 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001299 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300
1301MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1302 ChannelManager* channel_manager,
1303 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001304 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001305 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1306 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001308 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1310 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001311 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001312}
1313
ossudedfd282016-06-14 07:12:39 -07001314const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1315 const {
ossu075af922016-06-14 03:29:38 -07001316 return audio_sendrecv_codecs_;
1317}
1318
1319const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1320 return audio_send_codecs_;
1321}
1322
1323const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1324 return audio_recv_codecs_;
1325}
1326
1327void MediaSessionDescriptionFactory::set_audio_codecs(
1328 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1329 audio_send_codecs_ = send_codecs;
1330 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001331 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332}
1333
1334SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001335 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001336 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001337 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338
1339 StreamParamsVec current_streams;
1340 GetCurrentStreamParams(current_description, &current_streams);
1341
zhihuang1c378ed2017-08-17 14:10:50 -07001342 AudioCodecs offer_audio_codecs;
1343 VideoCodecs offer_video_codecs;
1344 DataCodecs offer_data_codecs;
1345 GetCodecsForOffer(current_description, &offer_audio_codecs,
1346 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001347
zhihuang1c378ed2017-08-17 14:10:50 -07001348 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001350 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351 }
zhihuang1c378ed2017-08-17 14:10:50 -07001352 FilterDataCodecs(&offer_data_codecs,
1353 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001354
1355 RtpHeaderExtensions audio_rtp_extensions;
1356 RtpHeaderExtensions video_rtp_extensions;
1357 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1358 &video_rtp_extensions);
1359
zhihuang1c378ed2017-08-17 14:10:50 -07001360 // Must have options for each existing section.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001361 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001362 RTC_DCHECK(current_description->contents().size() <=
1363 session_options.media_description_options.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001364 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001365
zhihuang1c378ed2017-08-17 14:10:50 -07001366 // Iterate through the media description options, matching with existing media
1367 // descriptions in |current_description|.
1368 int msection_index = 0;
1369 for (const MediaDescriptionOptions& media_description_options :
1370 session_options.media_description_options) {
1371 const ContentInfo* current_content = nullptr;
1372 if (current_description &&
1373 msection_index <
1374 static_cast<int>(current_description->contents().size())) {
1375 current_content = &current_description->contents()[msection_index];
1376 // Media type must match.
1377 RTC_DCHECK(IsMediaContentOfType(current_content,
1378 media_description_options.type));
1379 }
1380 switch (media_description_options.type) {
1381 case MEDIA_TYPE_AUDIO:
1382 if (!AddAudioContentForOffer(media_description_options, session_options,
1383 current_content, current_description,
1384 audio_rtp_extensions, offer_audio_codecs,
1385 &current_streams, offer.get())) {
1386 return nullptr;
1387 }
1388 break;
1389 case MEDIA_TYPE_VIDEO:
1390 if (!AddVideoContentForOffer(media_description_options, session_options,
1391 current_content, current_description,
1392 video_rtp_extensions, offer_video_codecs,
1393 &current_streams, offer.get())) {
1394 return nullptr;
1395 }
1396 break;
1397 case MEDIA_TYPE_DATA:
1398 if (!AddDataContentForOffer(media_description_options, session_options,
1399 current_content, current_description,
1400 offer_data_codecs, &current_streams,
1401 offer.get())) {
1402 return nullptr;
1403 }
1404 break;
1405 default:
1406 RTC_NOTREACHED();
1407 }
1408 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409 }
1410
1411 // Bundle the contents together, if we've been asked to do so, and update any
1412 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001413 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001415 for (const ContentInfo& content : offer->contents()) {
1416 // TODO(deadbeef): There are conditions that make bundling two media
1417 // descriptions together illegal. For example, they use the same payload
1418 // type to represent different codecs, or same IDs for different header
1419 // extensions. We need to detect this and not try to bundle those media
1420 // descriptions together.
1421 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001422 }
1423 offer->AddGroup(offer_bundle);
1424 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1425 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001426 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427 }
1428 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1429 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001430 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431 }
1432 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001433 return offer.release();
1434}
1435
1436SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001437 const SessionDescription* offer,
1438 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001439 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001440 if (!offer) {
1441 return nullptr;
1442 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001443 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001444 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1445 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001446 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001447
1448 StreamParamsVec current_streams;
1449 GetCurrentStreamParams(current_description, &current_streams);
1450
deadbeefb7892532017-02-22 19:35:18 -08001451 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1452 // group in the answer with the appropriate content names.
1453 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1454 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1455 // Transport info shared by the bundle group.
1456 std::unique_ptr<TransportInfo> bundle_transport;
1457
zhihuang1c378ed2017-08-17 14:10:50 -07001458 // Get list of all possible codecs that respects existing payload type
1459 // mappings and uses a single payload type space.
1460 //
1461 // Note that these lists may be further filtered for each m= section; this
1462 // step is done just to establish the payload type mappings shared by all
1463 // sections.
1464 AudioCodecs answer_audio_codecs;
1465 VideoCodecs answer_video_codecs;
1466 DataCodecs answer_data_codecs;
1467 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
1468 &answer_video_codecs, &answer_data_codecs);
1469
1470 if (!session_options.vad_enabled) {
1471 // If application doesn't want CN codecs in answer.
1472 StripCNCodecs(&answer_audio_codecs);
1473 }
1474 FilterDataCodecs(&answer_data_codecs,
1475 session_options.data_channel_type == DCT_SCTP);
1476
1477 // Must have options for exactly as many sections as in the offer.
1478 RTC_DCHECK(offer->contents().size() ==
1479 session_options.media_description_options.size());
1480 // Iterate through the media description options, matching with existing
1481 // media descriptions in |current_description|.
1482 int msection_index = 0;
1483 for (const MediaDescriptionOptions& media_description_options :
1484 session_options.media_description_options) {
1485 const ContentInfo* offer_content = &offer->contents()[msection_index];
1486 // Media types and MIDs must match between the remote offer and the
1487 // MediaDescriptionOptions.
1488 RTC_DCHECK(
1489 IsMediaContentOfType(offer_content, media_description_options.type));
1490 RTC_DCHECK(media_description_options.mid == offer_content->name);
1491 const ContentInfo* current_content = nullptr;
1492 if (current_description &&
1493 msection_index <
1494 static_cast<int>(current_description->contents().size())) {
1495 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001496 }
zhihuang1c378ed2017-08-17 14:10:50 -07001497 switch (media_description_options.type) {
1498 case MEDIA_TYPE_AUDIO:
1499 if (!AddAudioContentForAnswer(
1500 media_description_options, session_options, offer_content,
1501 offer, current_content, current_description,
1502 bundle_transport.get(), answer_audio_codecs, &current_streams,
1503 answer.get())) {
1504 return nullptr;
1505 }
1506 break;
1507 case MEDIA_TYPE_VIDEO:
1508 if (!AddVideoContentForAnswer(
1509 media_description_options, session_options, offer_content,
1510 offer, current_content, current_description,
1511 bundle_transport.get(), answer_video_codecs, &current_streams,
1512 answer.get())) {
1513 return nullptr;
1514 }
1515 break;
1516 case MEDIA_TYPE_DATA:
1517 if (!AddDataContentForAnswer(media_description_options, session_options,
1518 offer_content, offer, current_content,
1519 current_description,
1520 bundle_transport.get(), answer_data_codecs,
1521 &current_streams, answer.get())) {
1522 return nullptr;
1523 }
1524 break;
1525 default:
1526 RTC_NOTREACHED();
1527 }
1528 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001529 // See if we can add the newly generated m= section to the BUNDLE group in
1530 // the answer.
1531 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001532 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001533 offer_bundle->HasContentName(added.name)) {
1534 answer_bundle.AddContentName(added.name);
1535 bundle_transport.reset(
1536 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 }
1539
deadbeefb7892532017-02-22 19:35:18 -08001540 // Only put BUNDLE group in answer if nonempty.
1541 if (answer_bundle.FirstContentName()) {
1542 answer->AddGroup(answer_bundle);
1543
1544 // Share the same ICE credentials and crypto params across all contents,
1545 // as BUNDLE requires.
1546 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1547 LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1548 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550
deadbeefb7892532017-02-22 19:35:18 -08001551 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1552 LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1553 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554 }
1555 }
1556
1557 return answer.release();
1558}
1559
ossu075af922016-06-14 03:29:38 -07001560const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1561 const RtpTransceiverDirection& direction) const {
1562 // If stream is inactive - generate list as if sendrecv.
1563 if (direction.send == direction.recv) {
1564 return audio_sendrecv_codecs_;
1565 } else if (direction.send) {
1566 return audio_send_codecs_;
1567 } else {
1568 return audio_recv_codecs_;
1569 }
1570}
1571
1572const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1573 const RtpTransceiverDirection& offer,
1574 const RtpTransceiverDirection& answer) const {
1575 // For inactive and sendrecv answers, generate lists as if we were to accept
1576 // the offer's direction. See RFC 3264 Section 6.1.
1577 if (answer.send == answer.recv) {
1578 if (offer.send == offer.recv) {
1579 return audio_sendrecv_codecs_;
1580 } else if (offer.send) {
1581 return audio_recv_codecs_;
1582 } else {
1583 return audio_send_codecs_;
1584 }
1585 } else if (answer.send) {
1586 return audio_send_codecs_;
1587 } else {
1588 return audio_recv_codecs_;
1589 }
1590}
1591
zhihuang1c378ed2017-08-17 14:10:50 -07001592void MergeCodecsFromDescription(const SessionDescription* description,
1593 AudioCodecs* audio_codecs,
1594 VideoCodecs* video_codecs,
1595 DataCodecs* data_codecs,
1596 UsedPayloadTypes* used_pltypes) {
1597 RTC_DCHECK(description);
1598 for (const ContentInfo& content : description->contents()) {
1599 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1600 const AudioContentDescription* audio =
1601 static_cast<AudioContentDescription*>(content.description);
1602 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1603 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1604 const VideoContentDescription* video =
1605 static_cast<VideoContentDescription*>(content.description);
1606 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1607 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1608 const DataContentDescription* data =
1609 static_cast<DataContentDescription*>(content.description);
1610 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1611 }
1612 }
1613}
1614
1615// Getting codecs for an offer involves these steps:
1616//
1617// 1. Construct payload type -> codec mappings for current description.
1618// 2. Add any reference codecs that weren't already present
1619// 3. For each individual media description (m= section), filter codecs based
1620// on the directional attribute (happens in another method).
1621void MediaSessionDescriptionFactory::GetCodecsForOffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 const SessionDescription* current_description,
1623 AudioCodecs* audio_codecs,
1624 VideoCodecs* video_codecs,
1625 DataCodecs* data_codecs) const {
1626 UsedPayloadTypes used_pltypes;
1627 audio_codecs->clear();
1628 video_codecs->clear();
1629 data_codecs->clear();
1630
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001632 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1633 // new media type is added.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001635 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1636 data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637 }
1638
1639 // Add our codecs that are not in |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001640 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1641 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1642 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1643}
1644
1645// Getting codecs for an answer involves these steps:
1646//
1647// 1. Construct payload type -> codec mappings for current description.
1648// 2. Add any codecs from the offer that weren't already present.
1649// 3. Add any remaining codecs that weren't already present.
1650// 4. For each individual media description (m= section), filter codecs based
1651// on the directional attribute (happens in another method).
1652void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1653 const SessionDescription* current_description,
1654 const SessionDescription* remote_offer,
1655 AudioCodecs* audio_codecs,
1656 VideoCodecs* video_codecs,
1657 DataCodecs* data_codecs) const {
1658 UsedPayloadTypes used_pltypes;
1659 audio_codecs->clear();
1660 video_codecs->clear();
1661 data_codecs->clear();
1662
1663 // First - get all codecs from the current description if the media type
1664 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1665 // new media type is added.
1666 if (current_description) {
1667 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1668 data_codecs, &used_pltypes);
1669 }
1670
1671 // Second - filter out codecs that we don't support at all and should ignore.
1672 AudioCodecs filtered_offered_audio_codecs;
1673 VideoCodecs filtered_offered_video_codecs;
1674 DataCodecs filtered_offered_data_codecs;
1675 for (const ContentInfo& content : remote_offer->contents()) {
1676 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1677 const AudioContentDescription* audio =
1678 static_cast<AudioContentDescription*>(content.description);
1679 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1680 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1681 filtered_offered_audio_codecs,
1682 offered_audio_codec, nullptr) &&
1683 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1684 offered_audio_codec, nullptr)) {
1685 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1686 }
1687 }
1688 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1689 const VideoContentDescription* video =
1690 static_cast<VideoContentDescription*>(content.description);
1691 for (const VideoCodec& offered_video_codec : video->codecs()) {
1692 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1693 filtered_offered_video_codecs,
1694 offered_video_codec, nullptr) &&
1695 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1696 offered_video_codec, nullptr)) {
1697 filtered_offered_video_codecs.push_back(offered_video_codec);
1698 }
1699 }
1700 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1701 const DataContentDescription* data =
1702 static_cast<DataContentDescription*>(content.description);
1703 for (const DataCodec& offered_data_codec : data->codecs()) {
1704 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1705 filtered_offered_data_codecs,
1706 offered_data_codec, nullptr) &&
1707 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1708 offered_data_codec, nullptr)) {
1709 filtered_offered_data_codecs.push_back(offered_data_codec);
1710 }
1711 }
1712 }
1713 }
1714
1715 // Add codecs that are not in |current_description| but were in
1716 // |remote_offer|.
1717 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1718 &used_pltypes);
1719 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1720 &used_pltypes);
1721 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1722 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001723}
1724
1725void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1726 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001727 RtpHeaderExtensions* offer_audio_extensions,
1728 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001729 // All header extensions allocated from the same range to avoid potential
1730 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001732 RtpHeaderExtensions all_regular_extensions;
1733 RtpHeaderExtensions all_encrypted_extensions;
zhihuang1c378ed2017-08-17 14:10:50 -07001734 offer_audio_extensions->clear();
1735 offer_video_extensions->clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001736
1737 // First - get all extensions from the current description if the media type
1738 // is used.
1739 // Add them to |used_ids| so the local ids are not reused if a new media
1740 // type is added.
1741 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001742 for (const ContentInfo& content : current_description->contents()) {
1743 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1744 const AudioContentDescription* audio =
1745 static_cast<const AudioContentDescription*>(content.description);
1746 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1747 &all_regular_extensions, &all_encrypted_extensions,
1748 &used_ids);
1749 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1750 const VideoContentDescription* video =
1751 static_cast<const VideoContentDescription*>(content.description);
1752 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1753 &all_regular_extensions, &all_encrypted_extensions,
1754 &used_ids);
1755 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756 }
1757 }
1758
1759 // Add our default RTP header extensions that are not in
1760 // |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001761 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1762 &all_regular_extensions, &all_encrypted_extensions,
1763 &used_ids);
1764 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1765 &all_regular_extensions, &all_encrypted_extensions,
1766 &used_ids);
1767
jbauch5869f502017-06-29 12:31:36 -07001768 // TODO(jbauch): Support adding encrypted header extensions to existing
1769 // sessions.
1770 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001771 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1772 &all_encrypted_extensions, &used_ids);
1773 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1774 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001775 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001776}
1777
1778bool MediaSessionDescriptionFactory::AddTransportOffer(
1779 const std::string& content_name,
1780 const TransportOptions& transport_options,
1781 const SessionDescription* current_desc,
1782 SessionDescription* offer_desc) const {
1783 if (!transport_desc_factory_)
1784 return false;
1785 const TransportDescription* current_tdesc =
1786 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001787 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1789 bool ret = (new_tdesc.get() != NULL &&
1790 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1791 if (!ret) {
1792 LOG(LS_ERROR)
1793 << "Failed to AddTransportOffer, content name=" << content_name;
1794 }
1795 return ret;
1796}
1797
1798TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1799 const std::string& content_name,
1800 const SessionDescription* offer_desc,
1801 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001802 const SessionDescription* current_desc,
1803 bool require_transport_attributes) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001804 if (!transport_desc_factory_)
1805 return NULL;
1806 const TransportDescription* offer_tdesc =
1807 GetTransportDescription(content_name, offer_desc);
1808 const TransportDescription* current_tdesc =
1809 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001810 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1811 require_transport_attributes,
1812 current_tdesc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813}
1814
1815bool MediaSessionDescriptionFactory::AddTransportAnswer(
1816 const std::string& content_name,
1817 const TransportDescription& transport_desc,
1818 SessionDescription* answer_desc) const {
1819 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1820 transport_desc))) {
1821 LOG(LS_ERROR)
1822 << "Failed to AddTransportAnswer, content name=" << content_name;
1823 return false;
1824 }
1825 return true;
1826}
1827
zhihuang1c378ed2017-08-17 14:10:50 -07001828// |audio_codecs| = set of all possible codecs that can be used, with correct
1829// payload type mappings
1830//
1831// |supported_audio_codecs| = set of codecs that are supported for the direction
1832// of this m= section
1833//
1834// acd->codecs() = set of previously negotiated codecs for this m= section
1835//
1836// The payload types should come from audio_codecs, but the order should come
1837// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1838// change existing codec priority, and that new codecs are added with the right
1839// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001840bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001841 const MediaDescriptionOptions& media_description_options,
1842 const MediaSessionOptions& session_options,
1843 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001844 const SessionDescription* current_description,
1845 const RtpHeaderExtensions& audio_rtp_extensions,
1846 const AudioCodecs& audio_codecs,
1847 StreamParamsVec* current_streams,
1848 SessionDescription* desc) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001849 // Filter audio_codecs (which includes all codecs, with correctly remapped
1850 // payload types) based on transceiver direction.
1851 const AudioCodecs& supported_audio_codecs =
1852 GetAudioCodecsForOffer(media_description_options.direction);
1853
1854 AudioCodecs filtered_codecs;
1855 // Add the codecs from current content if exists.
1856 if (current_content) {
1857 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
1858 const AudioContentDescription* acd =
1859 static_cast<const AudioContentDescription*>(
1860 current_content->description);
1861 for (const AudioCodec& codec : acd->codecs()) {
1862 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1863 codec, nullptr)) {
1864 filtered_codecs.push_back(codec);
1865 }
1866 }
1867 }
1868 // Add other supported audio codecs.
1869 AudioCodec found_codec;
1870 for (const AudioCodec& codec : supported_audio_codecs) {
1871 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1872 codec, &found_codec) &&
1873 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1874 codec, nullptr)) {
1875 // Use the |found_codec| from |audio_codecs| because it has the correctly
1876 // mapped payload type.
1877 filtered_codecs.push_back(found_codec);
1878 }
1879 }
deadbeef44f08192015-12-15 16:20:09 -08001880
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001881 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001882 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1883 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001884
kwiberg31022942016-03-11 14:18:21 -08001885 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001886 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001887 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1888 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001889 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001890 media_description_options.sender_options, session_options,
1891 filtered_codecs, sdes_policy, GetCryptos(current_content),
1892 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001893 return false;
1894 }
1895 audio->set_lang(lang_);
1896
1897 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1898 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001899
zhihuang1c378ed2017-08-17 14:10:50 -07001900 audio->set_direction(
1901 media_description_options.direction.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001902
zhihuang1c378ed2017-08-17 14:10:50 -07001903 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1904 media_description_options.stopped, audio.release());
1905 if (!AddTransportOffer(media_description_options.mid,
1906 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001907 current_description, desc)) {
1908 return false;
1909 }
1910
1911 return true;
1912}
1913
1914bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001915 const MediaDescriptionOptions& media_description_options,
1916 const MediaSessionOptions& session_options,
1917 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001918 const SessionDescription* current_description,
1919 const RtpHeaderExtensions& video_rtp_extensions,
1920 const VideoCodecs& video_codecs,
1921 StreamParamsVec* current_streams,
1922 SessionDescription* desc) const {
1923 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001924 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1925 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001926
kwiberg31022942016-03-11 14:18:21 -08001927 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001928 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001929 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1930 &crypto_suites);
1931
1932 VideoCodecs filtered_codecs;
1933 // Add the codecs from current content if exists.
1934 if (current_content) {
1935 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
1936 const VideoContentDescription* vcd =
1937 static_cast<const VideoContentDescription*>(
1938 current_content->description);
1939 for (const VideoCodec& codec : vcd->codecs()) {
1940 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1941 nullptr)) {
1942 filtered_codecs.push_back(codec);
1943 }
1944 }
1945 }
1946 // Add other supported video codecs.
1947 VideoCodec found_codec;
1948 for (const VideoCodec& codec : video_codecs_) {
1949 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1950 &found_codec) &&
1951 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1952 nullptr)) {
1953 // Use the |found_codec| from |video_codecs| because it has the correctly
1954 // mapped payload type.
1955 filtered_codecs.push_back(found_codec);
1956 }
1957 }
1958
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001959 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001960 media_description_options.sender_options, session_options,
1961 filtered_codecs, sdes_policy, GetCryptos(current_content),
1962 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001963 return false;
1964 }
1965
zhihuang1c378ed2017-08-17 14:10:50 -07001966 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001967
1968 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1969 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001970
zhihuang1c378ed2017-08-17 14:10:50 -07001971 video->set_direction(
1972 media_description_options.direction.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001973
zhihuang1c378ed2017-08-17 14:10:50 -07001974 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1975 media_description_options.stopped, video.release());
1976 if (!AddTransportOffer(media_description_options.mid,
1977 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001978 current_description, desc)) {
1979 return false;
1980 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001981 return true;
1982}
1983
1984bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001985 const MediaDescriptionOptions& media_description_options,
1986 const MediaSessionOptions& session_options,
1987 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001988 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001989 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001990 StreamParamsVec* current_streams,
1991 SessionDescription* desc) const {
1992 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1993
kwiberg31022942016-03-11 14:18:21 -08001994 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07001995 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
1996 // If the DataChannel type is not specified, use the DataChannel type in
1997 // the current description.
1998 if (session_options.data_channel_type == DCT_NONE && current_content) {
1999 is_sctp = (static_cast<const DataContentDescription*>(
2000 current_content->description)
2001 ->protocol() == kMediaProtocolSctp);
2002 }
deadbeef44f08192015-12-15 16:20:09 -08002003
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002004 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07002005 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
2006 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002007 std::vector<std::string> crypto_suites;
2008 if (is_sctp) {
2009 // SDES doesn't make sense for SCTP, so we disable it, and we only
2010 // get SDES crypto suites for RTP-based data channels.
2011 sdes_policy = cricket::SEC_DISABLED;
2012 // Unlike SetMediaProtocol below, we need to set the protocol
2013 // before we call CreateMediaContentOffer. Otherwise,
2014 // CreateMediaContentOffer won't know this is SCTP and will
2015 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002016 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2017 // it's safe to do so. Older versions of webrtc would reject these
2018 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002019 data->set_protocol(
2020 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
2021 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002022 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002023 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002024 }
2025
zhihuang1c378ed2017-08-17 14:10:50 -07002026 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002027 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002028 media_description_options.sender_options, session_options,
2029 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2030 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002031 return false;
2032 }
2033
2034 if (is_sctp) {
zhihuang1c378ed2017-08-17 14:10:50 -07002035 desc->AddContent(media_description_options.mid, NS_JINGLE_DRAFT_SCTP,
2036 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002037 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002038 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002039 SetMediaProtocol(secure_transport, data.get());
zhihuang1c378ed2017-08-17 14:10:50 -07002040 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
2041 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002042 }
zhihuang1c378ed2017-08-17 14:10:50 -07002043 if (!AddTransportOffer(media_description_options.mid,
2044 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002045 current_description, desc)) {
2046 return false;
2047 }
2048 return true;
2049}
2050
zhihuang1c378ed2017-08-17 14:10:50 -07002051// |audio_codecs| = set of all possible codecs that can be used, with correct
2052// payload type mappings
2053//
2054// |supported_audio_codecs| = set of codecs that are supported for the direction
2055// of this m= section
2056//
2057// acd->codecs() = set of previously negotiated codecs for this m= section
2058//
2059// The payload types should come from audio_codecs, but the order should come
2060// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2061// change existing codec priority, and that new codecs are added with the right
2062// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002063bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002064 const MediaDescriptionOptions& media_description_options,
2065 const MediaSessionOptions& session_options,
2066 const ContentInfo* offer_content,
2067 const SessionDescription* offer_description,
2068 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002069 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002070 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002071 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002072 StreamParamsVec* current_streams,
2073 SessionDescription* answer) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002074 const AudioContentDescription* offer_audio_description =
2075 static_cast<const AudioContentDescription*>(offer_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002076
deadbeefb7892532017-02-22 19:35:18 -08002077 std::unique_ptr<TransportDescription> audio_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002078 CreateTransportAnswer(media_description_options.mid, offer_description,
2079 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002080 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002081 if (!audio_transport) {
2082 return false;
2083 }
2084
zhihuang1c378ed2017-08-17 14:10:50 -07002085 // Pick codecs based on the requested communications direction in the offer
2086 // and the selected direction in the answer.
2087 // Note these will be filtered one final time in CreateMediaContentAnswer.
2088 auto wants_rtd = media_description_options.direction;
2089 auto offer_rtd = RtpTransceiverDirection::FromMediaContentDirection(
2090 offer_audio_description->direction());
ossu075af922016-06-14 03:29:38 -07002091 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002092 AudioCodecs supported_audio_codecs =
2093 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2094
2095 AudioCodecs filtered_codecs;
2096 // Add the codecs from current content if exists.
2097 if (current_content) {
2098 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2099 const AudioContentDescription* acd =
2100 static_cast<const AudioContentDescription*>(
2101 current_content->description);
2102 for (const AudioCodec& codec : acd->codecs()) {
2103 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2104 codec, nullptr)) {
2105 filtered_codecs.push_back(codec);
2106 }
2107 }
2108 }
2109 // Add other supported audio codecs.
2110 AudioCodec found_codec;
2111 for (const AudioCodec& codec : supported_audio_codecs) {
2112 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2113 codec, &found_codec) &&
2114 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2115 codec, nullptr)) {
2116 // Use the |found_codec| from |audio_codecs| because it has the correctly
2117 // mapped payload type.
2118 filtered_codecs.push_back(found_codec);
2119 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002120 }
2121
zhihuang1c378ed2017-08-17 14:10:50 -07002122 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2123 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002124 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002125 new AudioContentDescription());
2126 // Do not require or create SDES cryptos if DTLS is used.
2127 cricket::SecurePolicy sdes_policy =
2128 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2129 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002130 offer_audio_description, media_description_options, session_options,
2131 filtered_codecs, sdes_policy, GetCryptos(current_content),
2132 audio_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2133 current_streams, bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002134 return false; // Fails the session setup.
2135 }
2136
deadbeefb7892532017-02-22 19:35:18 -08002137 bool secure = bundle_transport ? bundle_transport->description.secure()
2138 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002139 bool rejected = media_description_options.stopped ||
2140 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002141 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2142 audio_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002143 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002144 AddTransportAnswer(media_description_options.mid, *(audio_transport.get()),
2145 answer);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002146 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002147 LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2148 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002149 }
2150
zhihuang1c378ed2017-08-17 14:10:50 -07002151 answer->AddContent(media_description_options.mid, offer_content->type,
2152 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002153 return true;
2154}
2155
2156bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002157 const MediaDescriptionOptions& media_description_options,
2158 const MediaSessionOptions& session_options,
2159 const ContentInfo* offer_content,
2160 const SessionDescription* offer_description,
2161 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002162 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002163 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002164 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002165 StreamParamsVec* current_streams,
2166 SessionDescription* answer) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002167 const VideoContentDescription* offer_video_description =
2168 static_cast<const VideoContentDescription*>(offer_content->description);
2169
deadbeefb7892532017-02-22 19:35:18 -08002170 std::unique_ptr<TransportDescription> video_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002171 CreateTransportAnswer(media_description_options.mid, offer_description,
2172 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002173 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002174 if (!video_transport) {
2175 return false;
2176 }
2177
zhihuang1c378ed2017-08-17 14:10:50 -07002178 VideoCodecs filtered_codecs;
2179 // Add the codecs from current content if exists.
2180 if (current_content) {
2181 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2182 const VideoContentDescription* vcd =
2183 static_cast<const VideoContentDescription*>(
2184 current_content->description);
2185 for (const VideoCodec& codec : vcd->codecs()) {
2186 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2187 nullptr)) {
2188 filtered_codecs.push_back(codec);
2189 }
2190 }
2191 }
2192 // Add other supported video codecs.
2193 VideoCodec found_codec;
2194 for (const VideoCodec& codec : video_codecs_) {
2195 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2196 &found_codec) &&
2197 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2198 nullptr)) {
2199 // Use the |found_codec| from |video_codecs| because it has the correctly
2200 // mapped payload type.
2201 filtered_codecs.push_back(found_codec);
2202 }
2203 }
2204
2205 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2206 session_options.bundle_enabled;
2207
kwiberg31022942016-03-11 14:18:21 -08002208 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002209 new VideoContentDescription());
2210 // Do not require or create SDES cryptos if DTLS is used.
2211 cricket::SecurePolicy sdes_policy =
2212 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002213 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002214 offer_video_description, media_description_options, session_options,
2215 filtered_codecs, sdes_policy, GetCryptos(current_content),
2216 video_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2217 current_streams, bundle_enabled, video_answer.get())) {
2218 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002219 }
deadbeefb7892532017-02-22 19:35:18 -08002220 bool secure = bundle_transport ? bundle_transport->description.secure()
2221 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002222 bool rejected = media_description_options.stopped ||
2223 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002224 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2225 video_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002226 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002227 if (!AddTransportAnswer(media_description_options.mid,
2228 *(video_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002229 return false;
2230 }
zhihuang1c378ed2017-08-17 14:10:50 -07002231 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002232 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002233 LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2234 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002235 }
zhihuang1c378ed2017-08-17 14:10:50 -07002236 answer->AddContent(media_description_options.mid, offer_content->type,
2237 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002238 return true;
2239}
2240
2241bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002242 const MediaDescriptionOptions& media_description_options,
2243 const MediaSessionOptions& session_options,
2244 const ContentInfo* offer_content,
2245 const SessionDescription* offer_description,
2246 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002247 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002248 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002249 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002250 StreamParamsVec* current_streams,
2251 SessionDescription* answer) const {
deadbeefb7892532017-02-22 19:35:18 -08002252 std::unique_ptr<TransportDescription> data_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002253 CreateTransportAnswer(media_description_options.mid, offer_description,
2254 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002255 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002256 if (!data_transport) {
2257 return false;
2258 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002259
kwiberg31022942016-03-11 14:18:21 -08002260 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002261 new DataContentDescription());
2262 // Do not require or create SDES cryptos if DTLS is used.
2263 cricket::SecurePolicy sdes_policy =
2264 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002265 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2266 session_options.bundle_enabled;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002267 if (!CreateMediaContentAnswer(
2268 static_cast<const DataContentDescription*>(
zhihuang1c378ed2017-08-17 14:10:50 -07002269 offer_content->description),
2270 media_description_options, session_options, data_codecs, sdes_policy,
2271 GetCryptos(current_content), RtpHeaderExtensions(),
2272 enable_encrypted_rtp_header_extensions_, current_streams,
2273 bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002274 return false; // Fails the session setup.
2275 }
2276
zstein4b2e0822017-02-17 19:48:38 -08002277 // Respond with sctpmap if the offer uses sctpmap.
2278 const DataContentDescription* offer_data_description =
zhihuang1c378ed2017-08-17 14:10:50 -07002279 static_cast<const DataContentDescription*>(offer_content->description);
zstein4b2e0822017-02-17 19:48:38 -08002280 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2281 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2282
deadbeefb7892532017-02-22 19:35:18 -08002283 bool secure = bundle_transport ? bundle_transport->description.secure()
2284 : data_transport->secure();
2285
zhihuang1c378ed2017-08-17 14:10:50 -07002286 bool rejected = session_options.data_channel_type == DCT_NONE ||
2287 media_description_options.stopped ||
2288 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002289 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2290 data_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002291 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002292 data_answer->set_bandwidth(kDataMaxBandwidth);
2293 if (!AddTransportAnswer(media_description_options.mid,
2294 *(data_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002295 return false;
2296 }
2297 } else {
2298 // RFC 3264
2299 // The answer MUST contain the same number of m-lines as the offer.
2300 LOG(LS_INFO) << "Data is not supported in the answer.";
2301 }
zhihuang1c378ed2017-08-17 14:10:50 -07002302 answer->AddContent(media_description_options.mid, offer_content->type,
2303 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002304 return true;
2305}
2306
zhihuang1c378ed2017-08-17 14:10:50 -07002307void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2308 audio_sendrecv_codecs_.clear();
2309 all_audio_codecs_.clear();
2310 // Compute the audio codecs union.
2311 for (const AudioCodec& send : audio_send_codecs_) {
2312 all_audio_codecs_.push_back(send);
2313 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2314 send, nullptr)) {
2315 // It doesn't make sense to have an RTX codec we support sending but not
2316 // receiving.
2317 RTC_DCHECK(!IsRtxCodec(send));
2318 }
2319 }
2320 for (const AudioCodec& recv : audio_recv_codecs_) {
2321 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2322 recv, nullptr)) {
2323 all_audio_codecs_.push_back(recv);
2324 }
2325 }
2326 // Use NegotiateCodecs to merge our codec lists, since the operation is
2327 // essentially the same. Put send_codecs as the offered_codecs, which is the
2328 // order we'd like to follow. The reasoning is that encoding is usually more
2329 // expensive than decoding, and prioritizing a codec in the send list probably
2330 // means it's a codec we can handle efficiently.
2331 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2332 &audio_sendrecv_codecs_);
2333}
2334
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335bool IsMediaContent(const ContentInfo* content) {
2336 return (content &&
2337 (content->type == NS_JINGLE_RTP ||
2338 content->type == NS_JINGLE_DRAFT_SCTP));
2339}
2340
2341bool IsAudioContent(const ContentInfo* content) {
2342 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2343}
2344
2345bool IsVideoContent(const ContentInfo* content) {
2346 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2347}
2348
2349bool IsDataContent(const ContentInfo* content) {
2350 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2351}
2352
deadbeef0ed85b22016-02-23 17:24:52 -08002353const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2354 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002355 for (const ContentInfo& content : contents) {
2356 if (IsMediaContentOfType(&content, media_type)) {
2357 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358 }
2359 }
deadbeef0ed85b22016-02-23 17:24:52 -08002360 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361}
2362
2363const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2364 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2365}
2366
2367const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2368 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2369}
2370
2371const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2372 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2373}
2374
2375static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2376 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002377 if (sdesc == nullptr) {
2378 return nullptr;
2379 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380
2381 return GetFirstMediaContent(sdesc->contents(), media_type);
2382}
2383
2384const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2385 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2386}
2387
2388const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2389 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2390}
2391
2392const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2393 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2394}
2395
2396const MediaContentDescription* GetFirstMediaContentDescription(
2397 const SessionDescription* sdesc, MediaType media_type) {
2398 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2399 const ContentDescription* description = content ? content->description : NULL;
2400 return static_cast<const MediaContentDescription*>(description);
2401}
2402
2403const AudioContentDescription* GetFirstAudioContentDescription(
2404 const SessionDescription* sdesc) {
2405 return static_cast<const AudioContentDescription*>(
2406 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2407}
2408
2409const VideoContentDescription* GetFirstVideoContentDescription(
2410 const SessionDescription* sdesc) {
2411 return static_cast<const VideoContentDescription*>(
2412 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2413}
2414
2415const DataContentDescription* GetFirstDataContentDescription(
2416 const SessionDescription* sdesc) {
2417 return static_cast<const DataContentDescription*>(
2418 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2419}
2420
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002421//
2422// Non-const versions of the above functions.
2423//
2424
2425ContentInfo* GetFirstMediaContent(ContentInfos& contents,
2426 MediaType media_type) {
2427 for (ContentInfo& content : contents) {
2428 if (IsMediaContentOfType(&content, media_type)) {
2429 return &content;
2430 }
2431 }
2432 return nullptr;
2433}
2434
2435ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
2436 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2437}
2438
2439ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
2440 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2441}
2442
2443ContentInfo* GetFirstDataContent(ContentInfos& contents) {
2444 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2445}
2446
2447static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2448 MediaType media_type) {
2449 if (sdesc == nullptr) {
2450 return nullptr;
2451 }
2452
2453 return GetFirstMediaContent(sdesc->contents(), media_type);
2454}
2455
2456ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2457 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2458}
2459
2460ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2461 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2462}
2463
2464ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2465 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2466}
2467
2468MediaContentDescription* GetFirstMediaContentDescription(
2469 SessionDescription* sdesc,
2470 MediaType media_type) {
2471 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2472 ContentDescription* description = content ? content->description : NULL;
2473 return static_cast<MediaContentDescription*>(description);
2474}
2475
2476AudioContentDescription* GetFirstAudioContentDescription(
2477 SessionDescription* sdesc) {
2478 return static_cast<AudioContentDescription*>(
2479 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2480}
2481
2482VideoContentDescription* GetFirstVideoContentDescription(
2483 SessionDescription* sdesc) {
2484 return static_cast<VideoContentDescription*>(
2485 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2486}
2487
2488DataContentDescription* GetFirstDataContentDescription(
2489 SessionDescription* sdesc) {
2490 return static_cast<DataContentDescription*>(
2491 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2492}
2493
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002494} // namespace cricket