blob: 2d9fd94b059eecff2bc2e9e10a8e9606e941ba1c [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010011#include "webrtc/pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeef67cf2c12016-04-13 10:07:16 -070013#include <algorithm> // For std::find_if, std::sort.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <functional>
15#include <map>
kwiberg31022942016-03-11 14:18:21 -080016#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <set>
deadbeef67cf2c12016-04-13 10:07:16 -070018#include <unordered_map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <utility>
20
kwiberg84f6a3f2017-09-05 08:43:13 -070021#include "webrtc/api/optional.h"
nisse21e4e0b2017-02-20 05:01:01 -080022#include "webrtc/common_types.h"
kjellandera96e2d72016-02-04 23:52:28 -080023#include "webrtc/media/base/cryptoparams.h"
zhihuang38ede132017-06-15 12:52:32 -070024#include "webrtc/media/base/h264_profile_level_id.h"
kjellanderf4752772016-03-02 05:42:30 -080025#include "webrtc/media/base/mediaconstants.h"
26#include "webrtc/p2p/base/p2pconstants.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010027#include "webrtc/pc/channelmanager.h"
28#include "webrtc/pc/srtpfilter.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020029#include "webrtc/rtc_base/base64.h"
30#include "webrtc/rtc_base/checks.h"
31#include "webrtc/rtc_base/helpers.h"
32#include "webrtc/rtc_base/logging.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020033#include "webrtc/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;
501 stream_param.sync_label = sender.stream_id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 content_description->AddStream(stream_param);
503
504 // Store the new StreamParams in current_streams.
505 // This is necessary so that we can use the CNAME for other media types.
506 current_streams->push_back(stream_param);
507 } else {
deadbeef2f425aa2017-04-14 10:41:32 -0700508 // Use existing generated SSRCs/groups, but update the sync_label if
509 // necessary. This may be needed if a MediaStreamTrack was moved from one
510 // MediaStream to another.
zhihuang1c378ed2017-08-17 14:10:50 -0700511 param->sync_label = sender.stream_id;
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000512 content_description->AddStream(*param);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 }
514 }
515 return true;
516}
517
518// Updates the transport infos of the |sdesc| according to the given
519// |bundle_group|. The transport infos of the content names within the
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800520// |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
521// first content within the |bundle_group|.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
523 SessionDescription* sdesc) {
524 // The bundle should not be empty.
525 if (!sdesc || !bundle_group.FirstContentName()) {
526 return false;
527 }
528
529 // We should definitely have a transport for the first content.
jbauch083b73f2015-07-16 02:46:32 -0700530 const std::string& selected_content_name = *bundle_group.FirstContentName();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 const TransportInfo* selected_transport_info =
532 sdesc->GetTransportInfoByName(selected_content_name);
533 if (!selected_transport_info) {
534 return false;
535 }
536
537 // Set the other contents to use the same ICE credentials.
jbauch083b73f2015-07-16 02:46:32 -0700538 const std::string& selected_ufrag =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 selected_transport_info->description.ice_ufrag;
jbauch083b73f2015-07-16 02:46:32 -0700540 const std::string& selected_pwd =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 selected_transport_info->description.ice_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800542 ConnectionRole selected_connection_role =
543 selected_transport_info->description.connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 for (TransportInfos::iterator it =
545 sdesc->transport_infos().begin();
546 it != sdesc->transport_infos().end(); ++it) {
547 if (bundle_group.HasContentName(it->content_name) &&
548 it->content_name != selected_content_name) {
549 it->description.ice_ufrag = selected_ufrag;
550 it->description.ice_pwd = selected_pwd;
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800551 it->description.connection_role = selected_connection_role;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 }
553 }
554 return true;
555}
556
557// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
558// sets it to |cryptos|.
559static bool GetCryptosByName(const SessionDescription* sdesc,
560 const std::string& content_name,
561 CryptoParamsVec* cryptos) {
562 if (!sdesc || !cryptos) {
563 return false;
564 }
565
566 const ContentInfo* content = sdesc->GetContentByName(content_name);
567 if (!IsMediaContent(content) || !content->description) {
568 return false;
569 }
570
571 const MediaContentDescription* media_desc =
572 static_cast<const MediaContentDescription*>(content->description);
573 *cryptos = media_desc->cryptos();
574 return true;
575}
576
577// Predicate function used by the remove_if.
578// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
579static bool CryptoNotFound(const CryptoParams crypto,
580 const CryptoParamsVec* filter) {
581 if (filter == NULL) {
582 return true;
583 }
584 for (CryptoParamsVec::const_iterator it = filter->begin();
585 it != filter->end(); ++it) {
586 if (it->cipher_suite == crypto.cipher_suite) {
587 return false;
588 }
589 }
590 return true;
591}
592
593// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
594// which are not available in |filter|.
595static void PruneCryptos(const CryptoParamsVec& filter,
596 CryptoParamsVec* target_cryptos) {
597 if (!target_cryptos) {
598 return;
599 }
600 target_cryptos->erase(std::remove_if(target_cryptos->begin(),
601 target_cryptos->end(),
602 bind2nd(ptr_fun(CryptoNotFound),
603 &filter)),
604 target_cryptos->end());
605}
606
deadbeefb5cb19b2015-11-23 16:39:12 -0800607static bool IsRtpProtocol(const std::string& protocol) {
608 return protocol.empty() ||
609 (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
610}
611
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612static bool IsRtpContent(SessionDescription* sdesc,
613 const std::string& content_name) {
614 bool is_rtp = false;
615 ContentInfo* content = sdesc->GetContentByName(content_name);
616 if (IsMediaContent(content)) {
617 MediaContentDescription* media_desc =
618 static_cast<MediaContentDescription*>(content->description);
619 if (!media_desc) {
620 return false;
621 }
deadbeefb5cb19b2015-11-23 16:39:12 -0800622 is_rtp = IsRtpProtocol(media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 }
624 return is_rtp;
625}
626
627// Updates the crypto parameters of the |sdesc| according to the given
628// |bundle_group|. The crypto parameters of all the contents within the
629// |bundle_group| should be updated to use the common subset of the
630// available cryptos.
631static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
632 SessionDescription* sdesc) {
633 // The bundle should not be empty.
634 if (!sdesc || !bundle_group.FirstContentName()) {
635 return false;
636 }
637
wu@webrtc.org78187522013-10-07 23:32:02 +0000638 bool common_cryptos_needed = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 // Get the common cryptos.
640 const ContentNames& content_names = bundle_group.content_names();
641 CryptoParamsVec common_cryptos;
642 for (ContentNames::const_iterator it = content_names.begin();
643 it != content_names.end(); ++it) {
644 if (!IsRtpContent(sdesc, *it)) {
645 continue;
646 }
wu@webrtc.org78187522013-10-07 23:32:02 +0000647 // The common cryptos are needed if any of the content does not have DTLS
648 // enabled.
649 if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
650 common_cryptos_needed = true;
651 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 if (it == content_names.begin()) {
653 // Initial the common_cryptos with the first content in the bundle group.
654 if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
655 return false;
656 }
657 if (common_cryptos.empty()) {
658 // If there's no crypto params, we should just return.
659 return true;
660 }
661 } else {
662 CryptoParamsVec cryptos;
663 if (!GetCryptosByName(sdesc, *it, &cryptos)) {
664 return false;
665 }
666 PruneCryptos(cryptos, &common_cryptos);
667 }
668 }
669
wu@webrtc.org78187522013-10-07 23:32:02 +0000670 if (common_cryptos.empty() && common_cryptos_needed) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 return false;
672 }
673
674 // Update to use the common cryptos.
675 for (ContentNames::const_iterator it = content_names.begin();
676 it != content_names.end(); ++it) {
677 if (!IsRtpContent(sdesc, *it)) {
678 continue;
679 }
680 ContentInfo* content = sdesc->GetContentByName(*it);
681 if (IsMediaContent(content)) {
682 MediaContentDescription* media_desc =
683 static_cast<MediaContentDescription*>(content->description);
684 if (!media_desc) {
685 return false;
686 }
687 media_desc->set_cryptos(common_cryptos);
688 }
689 }
690 return true;
691}
692
693template <class C>
694static bool ContainsRtxCodec(const std::vector<C>& codecs) {
brandtr03d5fb12016-11-22 03:37:59 -0800695 for (const auto& codec : codecs) {
696 if (IsRtxCodec(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697 return true;
698 }
699 }
700 return false;
701}
702
703template <class C>
704static bool IsRtxCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800705 return STR_CASE_CMP(codec.name.c_str(), kRtxCodecName) == 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706}
707
brandtr03d5fb12016-11-22 03:37:59 -0800708template <class C>
709static bool ContainsFlexfecCodec(const std::vector<C>& codecs) {
710 for (const auto& codec : codecs) {
711 if (IsFlexfecCodec(codec)) {
712 return true;
713 }
714 }
715 return false;
716}
717
718template <class C>
719static bool IsFlexfecCodec(const C& codec) {
nisse21e4e0b2017-02-20 05:01:01 -0800720 return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
brandtr03d5fb12016-11-22 03:37:59 -0800721}
722
zhihuang1c378ed2017-08-17 14:10:50 -0700723// Create a media content to be offered for the given |sender_options|,
724// according to the given options.rtcp_mux, session_options.is_muc, codecs,
725// secure_transport, crypto, and current_streams. If we don't currently have
726// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
727// created (according to crypto_suites). The created content is added to the
728// offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729template <class C>
730static bool CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -0700731 const std::vector<SenderOptions>& sender_options,
732 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 const std::vector<C>& codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000734 const SecurePolicy& secure_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735 const CryptoParamsVec* current_cryptos,
736 const std::vector<std::string>& crypto_suites,
737 const RtpHeaderExtensions& rtp_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 StreamParamsVec* current_streams,
739 MediaContentDescriptionImpl<C>* offer) {
740 offer->AddCodecs(codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741
zhihuang1c378ed2017-08-17 14:10:50 -0700742 offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700743 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
744 offer->set_rtcp_reduced_size(true);
745 }
zhihuang1c378ed2017-08-17 14:10:50 -0700746 offer->set_multistream(session_options.is_muc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 offer->set_rtp_header_extensions(rtp_extensions);
748
zhihuang1c378ed2017-08-17 14:10:50 -0700749 if (!AddStreamParams(sender_options, session_options.rtcp_cname,
750 current_streams, offer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751 return false;
752 }
753
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 if (secure_policy != SEC_DISABLED) {
755 if (current_cryptos) {
756 AddMediaCryptos(*current_cryptos, offer);
757 }
758 if (offer->cryptos().empty()) {
759 if (!CreateMediaCryptos(crypto_suites, offer)) {
760 return false;
761 }
762 }
763 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764
deadbeef7af91dd2016-12-13 11:29:11 -0800765 if (secure_policy == SEC_REQUIRED && offer->cryptos().empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 return false;
767 }
768 return true;
769}
770
771template <class C>
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000772static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
magjedb05fa242016-11-11 04:00:16 -0800773 const int codec1_id,
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000774 const std::vector<C>& codecs2,
magjedb05fa242016-11-11 04:00:16 -0800775 const int codec2_id) {
776 const C* codec1 = FindCodecById(codecs1, codec1_id);
777 const C* codec2 = FindCodecById(codecs2, codec2_id);
778 return codec1 != nullptr && codec2 != nullptr && codec1->Matches(*codec2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000779}
780
781template <class C>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782static void NegotiateCodecs(const std::vector<C>& local_codecs,
783 const std::vector<C>& offered_codecs,
784 std::vector<C>* negotiated_codecs) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800785 for (const C& ours : local_codecs) {
786 C theirs;
deadbeef67cf2c12016-04-13 10:07:16 -0700787 // Note that we intentionally only find one matching codec for each of our
788 // local codecs, in case the remote offer contains duplicate codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800789 if (FindMatchingCodec(local_codecs, offered_codecs, ours, &theirs)) {
790 C negotiated = ours;
791 negotiated.IntersectFeedbackParams(theirs);
792 if (IsRtxCodec(negotiated)) {
magjedb05fa242016-11-11 04:00:16 -0800793 const auto apt_it =
794 theirs.params.find(kCodecParamAssociatedPayloadType);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800795 // FindMatchingCodec shouldn't return something with no apt value.
magjedb05fa242016-11-11 04:00:16 -0800796 RTC_DCHECK(apt_it != theirs.params.end());
797 negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_it->second);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 }
magjedf823ede2016-11-12 09:53:04 -0800799 if (CodecNamesEq(ours.name.c_str(), kH264CodecName)) {
800 webrtc::H264::GenerateProfileLevelIdForAnswer(
801 ours.params, theirs.params, &negotiated.params);
802 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800803 negotiated.id = theirs.id;
ossu075af922016-06-14 03:29:38 -0700804 negotiated.name = theirs.name;
magjedb05fa242016-11-11 04:00:16 -0800805 negotiated_codecs->push_back(std::move(negotiated));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 }
807 }
deadbeef67cf2c12016-04-13 10:07:16 -0700808 // RFC3264: Although the answerer MAY list the formats in their desired
809 // order of preference, it is RECOMMENDED that unless there is a
810 // specific reason, the answerer list formats in the same relative order
811 // they were present in the offer.
812 std::unordered_map<int, int> payload_type_preferences;
813 int preference = static_cast<int>(offered_codecs.size() + 1);
814 for (const C& codec : offered_codecs) {
815 payload_type_preferences[codec.id] = preference--;
816 }
817 std::sort(negotiated_codecs->begin(), negotiated_codecs->end(),
818 [&payload_type_preferences](const C& a, const C& b) {
819 return payload_type_preferences[a.id] >
820 payload_type_preferences[b.id];
821 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822}
823
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800824// Finds a codec in |codecs2| that matches |codec_to_match|, which is
825// a member of |codecs1|. If |codec_to_match| is an RTX codec, both
826// the codecs themselves and their associated codecs must match.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827template <class C>
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800828static bool FindMatchingCodec(const std::vector<C>& codecs1,
829 const std::vector<C>& codecs2,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 const C& codec_to_match,
831 C* found_codec) {
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800832 for (const C& potential_match : codecs2) {
833 if (potential_match.Matches(codec_to_match)) {
834 if (IsRtxCodec(codec_to_match)) {
magjedb05fa242016-11-11 04:00:16 -0800835 int apt_value_1 = 0;
836 int apt_value_2 = 0;
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800837 if (!codec_to_match.GetParam(kCodecParamAssociatedPayloadType,
838 &apt_value_1) ||
839 !potential_match.GetParam(kCodecParamAssociatedPayloadType,
840 &apt_value_2)) {
841 LOG(LS_WARNING) << "RTX missing associated payload type.";
842 continue;
843 }
844 if (!ReferencedCodecsMatch(codecs1, apt_value_1, codecs2,
845 apt_value_2)) {
846 continue;
847 }
848 }
849 if (found_codec) {
850 *found_codec = potential_match;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 }
852 return true;
853 }
854 }
855 return false;
856}
857
zhihuang1c378ed2017-08-17 14:10:50 -0700858// Find the codec in |codec_list| that |rtx_codec| is associated with.
859template <class C>
860static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
861 const C& rtx_codec) {
862 std::string associated_pt_str;
863 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
864 &associated_pt_str)) {
865 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
866 << " is missing an associated payload type.";
867 return nullptr;
868 }
869
870 int associated_pt;
871 if (!rtc::FromString(associated_pt_str, &associated_pt)) {
872 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
873 << " of RTX codec " << rtx_codec.name << " to an integer.";
874 return nullptr;
875 }
876
877 // Find the associated reference codec for the reference RTX codec.
878 const C* associated_codec = FindCodecById(codec_list, associated_pt);
879 if (!associated_codec) {
880 LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
881 << associated_pt << " for RTX codec " << rtx_codec.name
882 << ".";
883 }
884 return associated_codec;
885}
886
887// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888// already exist in |offered_codecs| and ensure the payload types don't
889// collide.
890template <class C>
zhihuang1c378ed2017-08-17 14:10:50 -0700891static void MergeCodecs(const std::vector<C>& reference_codecs,
892 std::vector<C>* offered_codecs,
893 UsedPayloadTypes* used_pltypes) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 // Add all new codecs that are not RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800895 for (const C& reference_codec : reference_codecs) {
896 if (!IsRtxCodec(reference_codec) &&
897 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
898 reference_codec, nullptr)) {
899 C codec = reference_codec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 used_pltypes->FindAndSetIdUsed(&codec);
901 offered_codecs->push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 }
903 }
904
905 // Add all new RTX codecs.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800906 for (const C& reference_codec : reference_codecs) {
907 if (IsRtxCodec(reference_codec) &&
908 !FindMatchingCodec<C>(reference_codecs, *offered_codecs,
909 reference_codec, nullptr)) {
910 C rtx_codec = reference_codec;
olka3c747662017-08-17 06:50:32 -0700911 const C* associated_codec =
zhihuang1c378ed2017-08-17 14:10:50 -0700912 GetAssociatedCodec(reference_codecs, rtx_codec);
olka3c747662017-08-17 06:50:32 -0700913 if (!associated_codec) {
olka3c747662017-08-17 06:50:32 -0700914 continue;
915 }
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800916 // Find a codec in the offered list that matches the reference codec.
917 // Its payload type may be different than the reference codec.
918 C matching_codec;
919 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
magjedb05fa242016-11-11 04:00:16 -0800920 *associated_codec, &matching_codec)) {
921 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -0800922 << " codec.";
923 continue;
924 }
925
926 rtx_codec.params[kCodecParamAssociatedPayloadType] =
927 rtc::ToString(matching_codec.id);
928 used_pltypes->FindAndSetIdUsed(&rtx_codec);
929 offered_codecs->push_back(rtx_codec);
930 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 }
932}
933
zhihuang1c378ed2017-08-17 14:10:50 -0700934static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
935 const webrtc::RtpExtension& ext_to_match,
936 webrtc::RtpExtension* found_extension) {
937 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
938 it != extensions.end(); ++it) {
939 // We assume that all URIs are given in a canonical format.
940 if (it->uri == ext_to_match.uri && it->encrypt == ext_to_match.encrypt) {
941 if (found_extension) {
942 *found_extension = *it;
943 }
944 return true;
945 }
946 }
947 return false;
948}
949
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000950static bool FindByUri(const RtpHeaderExtensions& extensions,
isheriff6f8d6862016-05-26 11:24:55 -0700951 const webrtc::RtpExtension& ext_to_match,
952 webrtc::RtpExtension* found_extension) {
jbauch5869f502017-06-29 12:31:36 -0700953 // We assume that all URIs are given in a canonical format.
954 const webrtc::RtpExtension* found =
955 webrtc::RtpExtension::FindHeaderExtensionByUri(extensions,
956 ext_to_match.uri);
957 if (!found) {
958 return false;
959 }
960 if (found_extension) {
961 *found_extension = *found;
962 }
963 return true;
964}
965
966static bool FindByUriWithEncryptionPreference(
967 const RtpHeaderExtensions& extensions,
968 const webrtc::RtpExtension& ext_to_match, bool encryption_preference,
969 webrtc::RtpExtension* found_extension) {
970 const webrtc::RtpExtension* unencrypted_extension = nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971 for (RtpHeaderExtensions::const_iterator it = extensions.begin();
972 it != extensions.end(); ++it) {
973 // We assume that all URIs are given in a canonical format.
974 if (it->uri == ext_to_match.uri) {
jbauch5869f502017-06-29 12:31:36 -0700975 if (!encryption_preference || it->encrypt) {
976 if (found_extension) {
977 *found_extension = *it;
978 }
979 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 }
jbauch5869f502017-06-29 12:31:36 -0700981 unencrypted_extension = &(*it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982 }
983 }
jbauch5869f502017-06-29 12:31:36 -0700984 if (unencrypted_extension) {
985 if (found_extension) {
986 *found_extension = *unencrypted_extension;
987 }
988 return true;
989 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 return false;
991}
992
zhihuang1c378ed2017-08-17 14:10:50 -0700993// Adds all extensions from |reference_extensions| to |offered_extensions| that
994// don't already exist in |offered_extensions| and ensure the IDs don't
995// collide. If an extension is added, it's also added to |regular_extensions| or
996// |encrypted_extensions|, and if the extension is in |regular_extensions| or
997// |encrypted_extensions|, its ID is marked as used in |used_ids|.
998// |offered_extensions| is for either audio or video while |regular_extensions|
999// and |encrypted_extensions| are used for both audio and video. There could be
1000// overlap between audio extensions and video extensions.
1001static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
1002 RtpHeaderExtensions* offered_extensions,
1003 RtpHeaderExtensions* regular_extensions,
1004 RtpHeaderExtensions* encrypted_extensions,
1005 UsedRtpHeaderExtensionIds* used_ids) {
olka3c747662017-08-17 06:50:32 -07001006 for (auto reference_extension : reference_extensions) {
zhihuang1c378ed2017-08-17 14:10:50 -07001007 if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
1008 nullptr)) {
olka3c747662017-08-17 06:50:32 -07001009 webrtc::RtpExtension existing;
zhihuang1c378ed2017-08-17 14:10:50 -07001010 if (reference_extension.encrypt) {
1011 if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
1012 &existing)) {
1013 offered_extensions->push_back(existing);
1014 } else {
1015 used_ids->FindAndSetIdUsed(&reference_extension);
1016 encrypted_extensions->push_back(reference_extension);
1017 offered_extensions->push_back(reference_extension);
1018 }
olka3c747662017-08-17 06:50:32 -07001019 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07001020 if (FindByUriAndEncryption(*regular_extensions, reference_extension,
1021 &existing)) {
1022 offered_extensions->push_back(existing);
1023 } else {
1024 used_ids->FindAndSetIdUsed(&reference_extension);
1025 regular_extensions->push_back(reference_extension);
1026 offered_extensions->push_back(reference_extension);
1027 }
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001028 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 }
1030 }
1031}
1032
jbauch5869f502017-06-29 12:31:36 -07001033static void AddEncryptedVersionsOfHdrExts(RtpHeaderExtensions* extensions,
1034 RtpHeaderExtensions* all_extensions,
1035 UsedRtpHeaderExtensionIds* used_ids) {
1036 RtpHeaderExtensions encrypted_extensions;
1037 for (const webrtc::RtpExtension& extension : *extensions) {
1038 webrtc::RtpExtension existing;
1039 // Don't add encrypted extensions again that were already included in a
1040 // previous offer or regular extensions that are also included as encrypted
1041 // extensions.
1042 if (extension.encrypt ||
1043 !webrtc::RtpExtension::IsEncryptionSupported(extension.uri) ||
1044 (FindByUriWithEncryptionPreference(*extensions, extension, true,
1045 &existing) && existing.encrypt)) {
1046 continue;
1047 }
1048
1049 if (FindByUri(*all_extensions, extension, &existing)) {
1050 encrypted_extensions.push_back(existing);
1051 } else {
1052 webrtc::RtpExtension encrypted(extension);
1053 encrypted.encrypt = true;
1054 used_ids->FindAndSetIdUsed(&encrypted);
1055 all_extensions->push_back(encrypted);
1056 encrypted_extensions.push_back(encrypted);
1057 }
1058 }
1059 extensions->insert(extensions->end(), encrypted_extensions.begin(),
1060 encrypted_extensions.end());
1061}
1062
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063static void NegotiateRtpHeaderExtensions(
1064 const RtpHeaderExtensions& local_extensions,
1065 const RtpHeaderExtensions& offered_extensions,
jbauch5869f502017-06-29 12:31:36 -07001066 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067 RtpHeaderExtensions* negotiated_extenstions) {
1068 RtpHeaderExtensions::const_iterator ours;
1069 for (ours = local_extensions.begin();
1070 ours != local_extensions.end(); ++ours) {
isheriff6f8d6862016-05-26 11:24:55 -07001071 webrtc::RtpExtension theirs;
jbauch5869f502017-06-29 12:31:36 -07001072 if (FindByUriWithEncryptionPreference(offered_extensions, *ours,
1073 enable_encrypted_rtp_header_extensions, &theirs)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 // We respond with their RTP header extension id.
1075 negotiated_extenstions->push_back(theirs);
1076 }
1077 }
1078}
1079
1080static void StripCNCodecs(AudioCodecs* audio_codecs) {
1081 AudioCodecs::iterator iter = audio_codecs->begin();
1082 while (iter != audio_codecs->end()) {
nisse21e4e0b2017-02-20 05:01:01 -08001083 if (STR_CASE_CMP(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084 iter = audio_codecs->erase(iter);
1085 } else {
1086 ++iter;
1087 }
1088 }
1089}
1090
zhihuang1c378ed2017-08-17 14:10:50 -07001091// Create a media content to be answered for the given |sender_options|
1092// according to the given session_options.rtcp_mux, session_options.streams,
1093// codecs, crypto, and current_streams. If we don't currently have crypto (in
1094// current_cryptos) and it is enabled (in secure_policy), crypto is created
1095// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
1096// negotiated with the offer. If the negotiation fails, this method returns
1097// false. The created content is added to the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098template <class C>
1099static bool CreateMediaContentAnswer(
1100 const MediaContentDescriptionImpl<C>* offer,
zhihuang1c378ed2017-08-17 14:10:50 -07001101 const MediaDescriptionOptions& media_description_options,
1102 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103 const std::vector<C>& local_codecs,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001104 const SecurePolicy& sdes_policy,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105 const CryptoParamsVec* current_cryptos,
1106 const RtpHeaderExtensions& local_rtp_extenstions,
jbauch5869f502017-06-29 12:31:36 -07001107 bool enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108 StreamParamsVec* current_streams,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109 bool bundle_enabled,
1110 MediaContentDescriptionImpl<C>* answer) {
1111 std::vector<C> negotiated_codecs;
1112 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
1113 answer->AddCodecs(negotiated_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114 answer->set_protocol(offer->protocol());
1115 RtpHeaderExtensions negotiated_rtp_extensions;
1116 NegotiateRtpHeaderExtensions(local_rtp_extenstions,
1117 offer->rtp_header_extensions(),
jbauch5869f502017-06-29 12:31:36 -07001118 enable_encrypted_rtp_header_extensions,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001119 &negotiated_rtp_extensions);
1120 answer->set_rtp_header_extensions(negotiated_rtp_extensions);
1121
zhihuang1c378ed2017-08-17 14:10:50 -07001122 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001123 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
1124 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
1125 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126
1127 if (sdes_policy != SEC_DISABLED) {
1128 CryptoParams crypto;
zhihuang1c378ed2017-08-17 14:10:50 -07001129 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
1130 &crypto)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 if (current_cryptos) {
1132 FindMatchingCrypto(*current_cryptos, crypto, &crypto);
1133 }
1134 answer->AddCrypto(crypto);
1135 }
1136 }
1137
deadbeef7af91dd2016-12-13 11:29:11 -08001138 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139 return false;
1140 }
1141
zhihuang1c378ed2017-08-17 14:10:50 -07001142 if (!AddStreamParams(media_description_options.sender_options,
1143 session_options.rtcp_cname, current_streams, answer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144 return false; // Something went seriously wrong.
1145 }
1146
ossu075af922016-06-14 03:29:38 -07001147 auto offer_rtd =
1148 RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07001149
1150 answer->set_direction(NegotiateRtpTransceiverDirection(
1151 offer_rtd, media_description_options.direction)
1152 .ToMediaContentDirection());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001153 return true;
1154}
1155
1156static bool IsMediaProtocolSupported(MediaType type,
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001157 const std::string& protocol,
1158 bool secure_transport) {
zhihuangcf5b37c2016-05-05 11:44:35 -07001159 // Since not all applications serialize and deserialize the media protocol,
1160 // we will have to accept |protocol| to be empty.
1161 if (protocol.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162 return true;
1163 }
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001164
zhihuangcf5b37c2016-05-05 11:44:35 -07001165 if (type == MEDIA_TYPE_DATA) {
1166 // Check for SCTP, but also for RTP for RTP-based data channels.
1167 // TODO(pthatcher): Remove RTP once RTP-based data channels are gone.
1168 if (secure_transport) {
1169 // Most likely scenarios first.
1170 return IsDtlsSctp(protocol) || IsDtlsRtp(protocol) ||
1171 IsPlainRtp(protocol);
1172 } else {
1173 return IsPlainSctp(protocol) || IsPlainRtp(protocol);
1174 }
1175 }
1176
1177 // Allow for non-DTLS RTP protocol even when using DTLS because that's what
1178 // JSEP specifies.
1179 if (secure_transport) {
1180 // Most likely scenarios first.
1181 return IsDtlsRtp(protocol) || IsPlainRtp(protocol);
1182 } else {
1183 return IsPlainRtp(protocol);
1184 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185}
1186
1187static void SetMediaProtocol(bool secure_transport,
1188 MediaContentDescription* desc) {
deadbeeff3938292015-07-15 12:20:53 -07001189 if (!desc->cryptos().empty())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 desc->set_protocol(kMediaProtocolSavpf);
deadbeeff3938292015-07-15 12:20:53 -07001191 else if (secure_transport)
1192 desc->set_protocol(kMediaProtocolDtlsSavpf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001193 else
1194 desc->set_protocol(kMediaProtocolAvpf);
1195}
1196
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001197// Gets the TransportInfo of the given |content_name| from the
1198// |current_description|. If doesn't exist, returns a new one.
1199static const TransportDescription* GetTransportDescription(
1200 const std::string& content_name,
1201 const SessionDescription* current_description) {
1202 const TransportDescription* desc = NULL;
1203 if (current_description) {
1204 const TransportInfo* info =
1205 current_description->GetTransportInfoByName(content_name);
1206 if (info) {
1207 desc = &info->description;
1208 }
1209 }
1210 return desc;
1211}
1212
1213// Gets the current DTLS state from the transport description.
zhihuang1c378ed2017-08-17 14:10:50 -07001214static bool IsDtlsActive(const ContentInfo* content,
1215 const SessionDescription* current_description) {
1216 if (!content) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001217 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001218 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001219
zhihuang1c378ed2017-08-17 14:10:50 -07001220 size_t msection_index = content - &current_description->contents()[0];
1221
1222 if (current_description->transport_infos().size() <= msection_index) {
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001223 return false;
zhihuang1c378ed2017-08-17 14:10:50 -07001224 }
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001225
zhihuang1c378ed2017-08-17 14:10:50 -07001226 return current_description->transport_infos()[msection_index]
1227 .description.secure();
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001228}
1229
ossu075af922016-06-14 03:29:38 -07001230std::string MediaContentDirectionToString(MediaContentDirection direction) {
1231 std::string dir_str;
1232 switch (direction) {
1233 case MD_INACTIVE:
1234 dir_str = "inactive";
1235 break;
1236 case MD_SENDONLY:
1237 dir_str = "sendonly";
1238 break;
1239 case MD_RECVONLY:
1240 dir_str = "recvonly";
1241 break;
1242 case MD_SENDRECV:
1243 dir_str = "sendrecv";
1244 break;
1245 default:
nissec80e7412017-01-11 05:56:46 -08001246 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07001247 break;
1248 }
1249
1250 return dir_str;
1251}
1252
zhihuang1c378ed2017-08-17 14:10:50 -07001253void MediaDescriptionOptions::AddAudioSender(const std::string& track_id,
1254 const std::string& stream_id) {
1255 RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
1256 AddSenderInternal(track_id, stream_id, 1);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001257}
1258
zhihuang1c378ed2017-08-17 14:10:50 -07001259void MediaDescriptionOptions::AddVideoSender(const std::string& track_id,
1260 const std::string& stream_id,
1261 int num_sim_layers) {
1262 RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
1263 AddSenderInternal(track_id, stream_id, num_sim_layers);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001264}
1265
zhihuang1c378ed2017-08-17 14:10:50 -07001266void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
1267 const std::string& stream_id) {
1268 RTC_DCHECK(type == MEDIA_TYPE_DATA);
1269 AddSenderInternal(track_id, stream_id, 1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270}
1271
zhihuang1c378ed2017-08-17 14:10:50 -07001272void MediaDescriptionOptions::AddSenderInternal(const std::string& track_id,
1273 const std::string& stream_id,
1274 int num_sim_layers) {
1275 sender_options.push_back(SenderOptions{track_id, stream_id, num_sim_layers});
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276}
1277
zhihuang1c378ed2017-08-17 14:10:50 -07001278bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
1279 return std::find_if(media_description_options.begin(),
1280 media_description_options.end(),
1281 [type](const MediaDescriptionOptions& t) {
1282 return t.type == type;
1283 }) != media_description_options.end();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001284}
1285
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1287 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001288 : transport_desc_factory_(transport_desc_factory) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289
1290MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
1291 ChannelManager* channel_manager,
1292 const TransportDescriptionFactory* transport_desc_factory)
zhihuang1c378ed2017-08-17 14:10:50 -07001293 : transport_desc_factory_(transport_desc_factory) {
ossudedfd282016-06-14 07:12:39 -07001294 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
1295 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
magjed3cf8ece2016-11-10 03:36:53 -08001297 channel_manager->GetSupportedVideoCodecs(&video_codecs_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
1299 channel_manager->GetSupportedDataCodecs(&data_codecs_);
zhihuang1c378ed2017-08-17 14:10:50 -07001300 ComputeAudioCodecsIntersectionAndUnion();
ossu075af922016-06-14 03:29:38 -07001301}
1302
ossudedfd282016-06-14 07:12:39 -07001303const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
1304 const {
ossu075af922016-06-14 03:29:38 -07001305 return audio_sendrecv_codecs_;
1306}
1307
1308const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const {
1309 return audio_send_codecs_;
1310}
1311
1312const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const {
1313 return audio_recv_codecs_;
1314}
1315
1316void MediaSessionDescriptionFactory::set_audio_codecs(
1317 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
1318 audio_send_codecs_ = send_codecs;
1319 audio_recv_codecs_ = recv_codecs;
zhihuang1c378ed2017-08-17 14:10:50 -07001320 ComputeAudioCodecsIntersectionAndUnion();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321}
1322
1323SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001324 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 const SessionDescription* current_description) const {
kwiberg31022942016-03-11 14:18:21 -08001326 std::unique_ptr<SessionDescription> offer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327
1328 StreamParamsVec current_streams;
1329 GetCurrentStreamParams(current_description, &current_streams);
1330
zhihuang1c378ed2017-08-17 14:10:50 -07001331 AudioCodecs offer_audio_codecs;
1332 VideoCodecs offer_video_codecs;
1333 DataCodecs offer_data_codecs;
1334 GetCodecsForOffer(current_description, &offer_audio_codecs,
1335 &offer_video_codecs, &offer_data_codecs);
ossu075af922016-06-14 03:29:38 -07001336
zhihuang1c378ed2017-08-17 14:10:50 -07001337 if (!session_options.vad_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338 // If application doesn't want CN codecs in offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001339 StripCNCodecs(&offer_audio_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340 }
zhihuang1c378ed2017-08-17 14:10:50 -07001341 FilterDataCodecs(&offer_data_codecs,
1342 session_options.data_channel_type == DCT_SCTP);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001343
1344 RtpHeaderExtensions audio_rtp_extensions;
1345 RtpHeaderExtensions video_rtp_extensions;
1346 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
1347 &video_rtp_extensions);
1348
zhihuang1c378ed2017-08-17 14:10:50 -07001349 // Must have options for each existing section.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001350 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001351 RTC_DCHECK(current_description->contents().size() <=
1352 session_options.media_description_options.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353 }
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001354
zhihuang1c378ed2017-08-17 14:10:50 -07001355 // Iterate through the media description options, matching with existing media
1356 // descriptions in |current_description|.
1357 int msection_index = 0;
1358 for (const MediaDescriptionOptions& media_description_options :
1359 session_options.media_description_options) {
1360 const ContentInfo* current_content = nullptr;
1361 if (current_description &&
1362 msection_index <
1363 static_cast<int>(current_description->contents().size())) {
1364 current_content = &current_description->contents()[msection_index];
1365 // Media type must match.
1366 RTC_DCHECK(IsMediaContentOfType(current_content,
1367 media_description_options.type));
1368 }
1369 switch (media_description_options.type) {
1370 case MEDIA_TYPE_AUDIO:
1371 if (!AddAudioContentForOffer(media_description_options, session_options,
1372 current_content, current_description,
1373 audio_rtp_extensions, offer_audio_codecs,
1374 &current_streams, offer.get())) {
1375 return nullptr;
1376 }
1377 break;
1378 case MEDIA_TYPE_VIDEO:
1379 if (!AddVideoContentForOffer(media_description_options, session_options,
1380 current_content, current_description,
1381 video_rtp_extensions, offer_video_codecs,
1382 &current_streams, offer.get())) {
1383 return nullptr;
1384 }
1385 break;
1386 case MEDIA_TYPE_DATA:
1387 if (!AddDataContentForOffer(media_description_options, session_options,
1388 current_content, current_description,
1389 offer_data_codecs, &current_streams,
1390 offer.get())) {
1391 return nullptr;
1392 }
1393 break;
1394 default:
1395 RTC_NOTREACHED();
1396 }
1397 ++msection_index;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001398 }
1399
1400 // Bundle the contents together, if we've been asked to do so, and update any
1401 // parameters that need to be tweaked for BUNDLE.
zhihuang1c378ed2017-08-17 14:10:50 -07001402 if (session_options.bundle_enabled && offer->contents().size() > 0u) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
zhihuang1c378ed2017-08-17 14:10:50 -07001404 for (const ContentInfo& content : offer->contents()) {
1405 // TODO(deadbeef): There are conditions that make bundling two media
1406 // descriptions together illegal. For example, they use the same payload
1407 // type to represent different codecs, or same IDs for different header
1408 // extensions. We need to detect this and not try to bundle those media
1409 // descriptions together.
1410 offer_bundle.AddContentName(content.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001411 }
1412 offer->AddGroup(offer_bundle);
1413 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
1414 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001415 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 }
1417 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
1418 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
zhihuang1c378ed2017-08-17 14:10:50 -07001419 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420 }
1421 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001422 return offer.release();
1423}
1424
1425SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07001426 const SessionDescription* offer,
1427 const MediaSessionOptions& session_options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001428 const SessionDescription* current_description) const {
deadbeefb7892532017-02-22 19:35:18 -08001429 if (!offer) {
1430 return nullptr;
1431 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432 // The answer contains the intersection of the codecs in the offer with the
deadbeef67cf2c12016-04-13 10:07:16 -07001433 // codecs we support. As indicated by XEP-0167, we retain the same payload ids
1434 // from the offer in the answer.
kwiberg31022942016-03-11 14:18:21 -08001435 std::unique_ptr<SessionDescription> answer(new SessionDescription());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436
1437 StreamParamsVec current_streams;
1438 GetCurrentStreamParams(current_description, &current_streams);
1439
deadbeefb7892532017-02-22 19:35:18 -08001440 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
1441 // group in the answer with the appropriate content names.
1442 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
1443 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
1444 // Transport info shared by the bundle group.
1445 std::unique_ptr<TransportInfo> bundle_transport;
1446
zhihuang1c378ed2017-08-17 14:10:50 -07001447 // Get list of all possible codecs that respects existing payload type
1448 // mappings and uses a single payload type space.
1449 //
1450 // Note that these lists may be further filtered for each m= section; this
1451 // step is done just to establish the payload type mappings shared by all
1452 // sections.
1453 AudioCodecs answer_audio_codecs;
1454 VideoCodecs answer_video_codecs;
1455 DataCodecs answer_data_codecs;
1456 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
1457 &answer_video_codecs, &answer_data_codecs);
1458
1459 if (!session_options.vad_enabled) {
1460 // If application doesn't want CN codecs in answer.
1461 StripCNCodecs(&answer_audio_codecs);
1462 }
1463 FilterDataCodecs(&answer_data_codecs,
1464 session_options.data_channel_type == DCT_SCTP);
1465
1466 // Must have options for exactly as many sections as in the offer.
1467 RTC_DCHECK(offer->contents().size() ==
1468 session_options.media_description_options.size());
1469 // Iterate through the media description options, matching with existing
1470 // media descriptions in |current_description|.
1471 int msection_index = 0;
1472 for (const MediaDescriptionOptions& media_description_options :
1473 session_options.media_description_options) {
1474 const ContentInfo* offer_content = &offer->contents()[msection_index];
1475 // Media types and MIDs must match between the remote offer and the
1476 // MediaDescriptionOptions.
1477 RTC_DCHECK(
1478 IsMediaContentOfType(offer_content, media_description_options.type));
1479 RTC_DCHECK(media_description_options.mid == offer_content->name);
1480 const ContentInfo* current_content = nullptr;
1481 if (current_description &&
1482 msection_index <
1483 static_cast<int>(current_description->contents().size())) {
1484 current_content = &current_description->contents()[msection_index];
deadbeefb7892532017-02-22 19:35:18 -08001485 }
zhihuang1c378ed2017-08-17 14:10:50 -07001486 switch (media_description_options.type) {
1487 case MEDIA_TYPE_AUDIO:
1488 if (!AddAudioContentForAnswer(
1489 media_description_options, session_options, offer_content,
1490 offer, current_content, current_description,
1491 bundle_transport.get(), answer_audio_codecs, &current_streams,
1492 answer.get())) {
1493 return nullptr;
1494 }
1495 break;
1496 case MEDIA_TYPE_VIDEO:
1497 if (!AddVideoContentForAnswer(
1498 media_description_options, session_options, offer_content,
1499 offer, current_content, current_description,
1500 bundle_transport.get(), answer_video_codecs, &current_streams,
1501 answer.get())) {
1502 return nullptr;
1503 }
1504 break;
1505 case MEDIA_TYPE_DATA:
1506 if (!AddDataContentForAnswer(media_description_options, session_options,
1507 offer_content, offer, current_content,
1508 current_description,
1509 bundle_transport.get(), answer_data_codecs,
1510 &current_streams, answer.get())) {
1511 return nullptr;
1512 }
1513 break;
1514 default:
1515 RTC_NOTREACHED();
1516 }
1517 ++msection_index;
deadbeefb7892532017-02-22 19:35:18 -08001518 // See if we can add the newly generated m= section to the BUNDLE group in
1519 // the answer.
1520 ContentInfo& added = answer->contents().back();
zhihuang1c378ed2017-08-17 14:10:50 -07001521 if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
deadbeefb7892532017-02-22 19:35:18 -08001522 offer_bundle->HasContentName(added.name)) {
1523 answer_bundle.AddContentName(added.name);
1524 bundle_transport.reset(
1525 new TransportInfo(*answer->GetTransportInfoByName(added.name)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001527 }
1528
deadbeefb7892532017-02-22 19:35:18 -08001529 // Only put BUNDLE group in answer if nonempty.
1530 if (answer_bundle.FirstContentName()) {
1531 answer->AddGroup(answer_bundle);
1532
1533 // Share the same ICE credentials and crypto params across all contents,
1534 // as BUNDLE requires.
1535 if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
1536 LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
1537 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001539
deadbeefb7892532017-02-22 19:35:18 -08001540 if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
1541 LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
1542 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 }
1544 }
1545
1546 return answer.release();
1547}
1548
ossu075af922016-06-14 03:29:38 -07001549const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
1550 const RtpTransceiverDirection& direction) const {
1551 // If stream is inactive - generate list as if sendrecv.
1552 if (direction.send == direction.recv) {
1553 return audio_sendrecv_codecs_;
1554 } else if (direction.send) {
1555 return audio_send_codecs_;
1556 } else {
1557 return audio_recv_codecs_;
1558 }
1559}
1560
1561const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
1562 const RtpTransceiverDirection& offer,
1563 const RtpTransceiverDirection& answer) const {
1564 // For inactive and sendrecv answers, generate lists as if we were to accept
1565 // the offer's direction. See RFC 3264 Section 6.1.
1566 if (answer.send == answer.recv) {
1567 if (offer.send == offer.recv) {
1568 return audio_sendrecv_codecs_;
1569 } else if (offer.send) {
1570 return audio_recv_codecs_;
1571 } else {
1572 return audio_send_codecs_;
1573 }
1574 } else if (answer.send) {
1575 return audio_send_codecs_;
1576 } else {
1577 return audio_recv_codecs_;
1578 }
1579}
1580
zhihuang1c378ed2017-08-17 14:10:50 -07001581void MergeCodecsFromDescription(const SessionDescription* description,
1582 AudioCodecs* audio_codecs,
1583 VideoCodecs* video_codecs,
1584 DataCodecs* data_codecs,
1585 UsedPayloadTypes* used_pltypes) {
1586 RTC_DCHECK(description);
1587 for (const ContentInfo& content : description->contents()) {
1588 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1589 const AudioContentDescription* audio =
1590 static_cast<AudioContentDescription*>(content.description);
1591 MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
1592 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1593 const VideoContentDescription* video =
1594 static_cast<VideoContentDescription*>(content.description);
1595 MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
1596 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1597 const DataContentDescription* data =
1598 static_cast<DataContentDescription*>(content.description);
1599 MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
1600 }
1601 }
1602}
1603
1604// Getting codecs for an offer involves these steps:
1605//
1606// 1. Construct payload type -> codec mappings for current description.
1607// 2. Add any reference codecs that weren't already present
1608// 3. For each individual media description (m= section), filter codecs based
1609// on the directional attribute (happens in another method).
1610void MediaSessionDescriptionFactory::GetCodecsForOffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611 const SessionDescription* current_description,
1612 AudioCodecs* audio_codecs,
1613 VideoCodecs* video_codecs,
1614 DataCodecs* data_codecs) const {
1615 UsedPayloadTypes used_pltypes;
1616 audio_codecs->clear();
1617 video_codecs->clear();
1618 data_codecs->clear();
1619
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620 // First - get all codecs from the current description if the media type
zhihuang1c378ed2017-08-17 14:10:50 -07001621 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1622 // new media type is added.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001624 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1625 data_codecs, &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 }
1627
1628 // Add our codecs that are not in |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001629 MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
1630 MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
1631 MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
1632}
1633
1634// Getting codecs for an answer involves these steps:
1635//
1636// 1. Construct payload type -> codec mappings for current description.
1637// 2. Add any codecs from the offer that weren't already present.
1638// 3. Add any remaining codecs that weren't already present.
1639// 4. For each individual media description (m= section), filter codecs based
1640// on the directional attribute (happens in another method).
1641void MediaSessionDescriptionFactory::GetCodecsForAnswer(
1642 const SessionDescription* current_description,
1643 const SessionDescription* remote_offer,
1644 AudioCodecs* audio_codecs,
1645 VideoCodecs* video_codecs,
1646 DataCodecs* data_codecs) const {
1647 UsedPayloadTypes used_pltypes;
1648 audio_codecs->clear();
1649 video_codecs->clear();
1650 data_codecs->clear();
1651
1652 // First - get all codecs from the current description if the media type
1653 // is used. Add them to |used_pltypes| so the payload type is not reused if a
1654 // new media type is added.
1655 if (current_description) {
1656 MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
1657 data_codecs, &used_pltypes);
1658 }
1659
1660 // Second - filter out codecs that we don't support at all and should ignore.
1661 AudioCodecs filtered_offered_audio_codecs;
1662 VideoCodecs filtered_offered_video_codecs;
1663 DataCodecs filtered_offered_data_codecs;
1664 for (const ContentInfo& content : remote_offer->contents()) {
1665 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1666 const AudioContentDescription* audio =
1667 static_cast<AudioContentDescription*>(content.description);
1668 for (const AudioCodec& offered_audio_codec : audio->codecs()) {
1669 if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
1670 filtered_offered_audio_codecs,
1671 offered_audio_codec, nullptr) &&
1672 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
1673 offered_audio_codec, nullptr)) {
1674 filtered_offered_audio_codecs.push_back(offered_audio_codec);
1675 }
1676 }
1677 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1678 const VideoContentDescription* video =
1679 static_cast<VideoContentDescription*>(content.description);
1680 for (const VideoCodec& offered_video_codec : video->codecs()) {
1681 if (!FindMatchingCodec<VideoCodec>(video->codecs(),
1682 filtered_offered_video_codecs,
1683 offered_video_codec, nullptr) &&
1684 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
1685 offered_video_codec, nullptr)) {
1686 filtered_offered_video_codecs.push_back(offered_video_codec);
1687 }
1688 }
1689 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
1690 const DataContentDescription* data =
1691 static_cast<DataContentDescription*>(content.description);
1692 for (const DataCodec& offered_data_codec : data->codecs()) {
1693 if (!FindMatchingCodec<DataCodec>(data->codecs(),
1694 filtered_offered_data_codecs,
1695 offered_data_codec, nullptr) &&
1696 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
1697 offered_data_codec, nullptr)) {
1698 filtered_offered_data_codecs.push_back(offered_data_codec);
1699 }
1700 }
1701 }
1702 }
1703
1704 // Add codecs that are not in |current_description| but were in
1705 // |remote_offer|.
1706 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
1707 &used_pltypes);
1708 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
1709 &used_pltypes);
1710 MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
1711 &used_pltypes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712}
1713
1714void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
1715 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001716 RtpHeaderExtensions* offer_audio_extensions,
1717 RtpHeaderExtensions* offer_video_extensions) const {
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001718 // All header extensions allocated from the same range to avoid potential
1719 // issues when using BUNDLE.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720 UsedRtpHeaderExtensionIds used_ids;
jbauch5869f502017-06-29 12:31:36 -07001721 RtpHeaderExtensions all_regular_extensions;
1722 RtpHeaderExtensions all_encrypted_extensions;
zhihuang1c378ed2017-08-17 14:10:50 -07001723 offer_audio_extensions->clear();
1724 offer_video_extensions->clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725
1726 // First - get all extensions from the current description if the media type
1727 // is used.
1728 // Add them to |used_ids| so the local ids are not reused if a new media
1729 // type is added.
1730 if (current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001731 for (const ContentInfo& content : current_description->contents()) {
1732 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
1733 const AudioContentDescription* audio =
1734 static_cast<const AudioContentDescription*>(content.description);
1735 MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
1736 &all_regular_extensions, &all_encrypted_extensions,
1737 &used_ids);
1738 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
1739 const VideoContentDescription* video =
1740 static_cast<const VideoContentDescription*>(content.description);
1741 MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
1742 &all_regular_extensions, &all_encrypted_extensions,
1743 &used_ids);
1744 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001745 }
1746 }
1747
1748 // Add our default RTP header extensions that are not in
1749 // |current_description|.
zhihuang1c378ed2017-08-17 14:10:50 -07001750 MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
1751 &all_regular_extensions, &all_encrypted_extensions,
1752 &used_ids);
1753 MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
1754 &all_regular_extensions, &all_encrypted_extensions,
1755 &used_ids);
1756
jbauch5869f502017-06-29 12:31:36 -07001757 // TODO(jbauch): Support adding encrypted header extensions to existing
1758 // sessions.
1759 if (enable_encrypted_rtp_header_extensions_ && !current_description) {
zhihuang1c378ed2017-08-17 14:10:50 -07001760 AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
1761 &all_encrypted_extensions, &used_ids);
1762 AddEncryptedVersionsOfHdrExts(offer_video_extensions,
1763 &all_encrypted_extensions, &used_ids);
jbauch5869f502017-06-29 12:31:36 -07001764 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001765}
1766
1767bool MediaSessionDescriptionFactory::AddTransportOffer(
1768 const std::string& content_name,
1769 const TransportOptions& transport_options,
1770 const SessionDescription* current_desc,
1771 SessionDescription* offer_desc) const {
1772 if (!transport_desc_factory_)
1773 return false;
1774 const TransportDescription* current_tdesc =
1775 GetTransportDescription(content_name, current_desc);
kwiberg31022942016-03-11 14:18:21 -08001776 std::unique_ptr<TransportDescription> new_tdesc(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
1778 bool ret = (new_tdesc.get() != NULL &&
1779 offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
1780 if (!ret) {
1781 LOG(LS_ERROR)
1782 << "Failed to AddTransportOffer, content name=" << content_name;
1783 }
1784 return ret;
1785}
1786
1787TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
1788 const std::string& content_name,
1789 const SessionDescription* offer_desc,
1790 const TransportOptions& transport_options,
deadbeefb7892532017-02-22 19:35:18 -08001791 const SessionDescription* current_desc,
1792 bool require_transport_attributes) const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001793 if (!transport_desc_factory_)
1794 return NULL;
1795 const TransportDescription* offer_tdesc =
1796 GetTransportDescription(content_name, offer_desc);
1797 const TransportDescription* current_tdesc =
1798 GetTransportDescription(content_name, current_desc);
deadbeefb7892532017-02-22 19:35:18 -08001799 return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
1800 require_transport_attributes,
1801 current_tdesc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802}
1803
1804bool MediaSessionDescriptionFactory::AddTransportAnswer(
1805 const std::string& content_name,
1806 const TransportDescription& transport_desc,
1807 SessionDescription* answer_desc) const {
1808 if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
1809 transport_desc))) {
1810 LOG(LS_ERROR)
1811 << "Failed to AddTransportAnswer, content name=" << content_name;
1812 return false;
1813 }
1814 return true;
1815}
1816
zhihuang1c378ed2017-08-17 14:10:50 -07001817// |audio_codecs| = set of all possible codecs that can be used, with correct
1818// payload type mappings
1819//
1820// |supported_audio_codecs| = set of codecs that are supported for the direction
1821// of this m= section
1822//
1823// acd->codecs() = set of previously negotiated codecs for this m= section
1824//
1825// The payload types should come from audio_codecs, but the order should come
1826// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
1827// change existing codec priority, and that new codecs are added with the right
1828// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001829bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001830 const MediaDescriptionOptions& media_description_options,
1831 const MediaSessionOptions& session_options,
1832 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001833 const SessionDescription* current_description,
1834 const RtpHeaderExtensions& audio_rtp_extensions,
1835 const AudioCodecs& audio_codecs,
1836 StreamParamsVec* current_streams,
1837 SessionDescription* desc) const {
zhihuang1c378ed2017-08-17 14:10:50 -07001838 // Filter audio_codecs (which includes all codecs, with correctly remapped
1839 // payload types) based on transceiver direction.
1840 const AudioCodecs& supported_audio_codecs =
1841 GetAudioCodecsForOffer(media_description_options.direction);
1842
1843 AudioCodecs filtered_codecs;
1844 // Add the codecs from current content if exists.
1845 if (current_content) {
1846 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
1847 const AudioContentDescription* acd =
1848 static_cast<const AudioContentDescription*>(
1849 current_content->description);
1850 for (const AudioCodec& codec : acd->codecs()) {
1851 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1852 codec, nullptr)) {
1853 filtered_codecs.push_back(codec);
1854 }
1855 }
1856 }
1857 // Add other supported audio codecs.
1858 AudioCodec found_codec;
1859 for (const AudioCodec& codec : supported_audio_codecs) {
1860 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
1861 codec, &found_codec) &&
1862 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
1863 codec, nullptr)) {
1864 // Use the |found_codec| from |audio_codecs| because it has the correctly
1865 // mapped payload type.
1866 filtered_codecs.push_back(found_codec);
1867 }
1868 }
deadbeef44f08192015-12-15 16:20:09 -08001869
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001870 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001871 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1872 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001873
kwiberg31022942016-03-11 14:18:21 -08001874 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001875 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001876 GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
1877 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001878 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001879 media_description_options.sender_options, session_options,
1880 filtered_codecs, sdes_policy, GetCryptos(current_content),
1881 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001882 return false;
1883 }
1884 audio->set_lang(lang_);
1885
1886 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1887 SetMediaProtocol(secure_transport, audio.get());
jiayl@webrtc.org7d4891d2014-09-09 21:43:15 +00001888
zhihuang1c378ed2017-08-17 14:10:50 -07001889 audio->set_direction(
1890 media_description_options.direction.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001891
zhihuang1c378ed2017-08-17 14:10:50 -07001892 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1893 media_description_options.stopped, audio.release());
1894 if (!AddTransportOffer(media_description_options.mid,
1895 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001896 current_description, desc)) {
1897 return false;
1898 }
1899
1900 return true;
1901}
1902
1903bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001904 const MediaDescriptionOptions& media_description_options,
1905 const MediaSessionOptions& session_options,
1906 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001907 const SessionDescription* current_description,
1908 const RtpHeaderExtensions& video_rtp_extensions,
1909 const VideoCodecs& video_codecs,
1910 StreamParamsVec* current_streams,
1911 SessionDescription* desc) const {
1912 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001913 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1914 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001915
kwiberg31022942016-03-11 14:18:21 -08001916 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001917 std::vector<std::string> crypto_suites;
zhihuang1c378ed2017-08-17 14:10:50 -07001918 GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
1919 &crypto_suites);
1920
1921 VideoCodecs filtered_codecs;
1922 // Add the codecs from current content if exists.
1923 if (current_content) {
1924 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
1925 const VideoContentDescription* vcd =
1926 static_cast<const VideoContentDescription*>(
1927 current_content->description);
1928 for (const VideoCodec& codec : vcd->codecs()) {
1929 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1930 nullptr)) {
1931 filtered_codecs.push_back(codec);
1932 }
1933 }
1934 }
1935 // Add other supported video codecs.
1936 VideoCodec found_codec;
1937 for (const VideoCodec& codec : video_codecs_) {
1938 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
1939 &found_codec) &&
1940 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
1941 nullptr)) {
1942 // Use the |found_codec| from |video_codecs| because it has the correctly
1943 // mapped payload type.
1944 filtered_codecs.push_back(found_codec);
1945 }
1946 }
1947
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001948 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001949 media_description_options.sender_options, session_options,
1950 filtered_codecs, sdes_policy, GetCryptos(current_content),
1951 crypto_suites, video_rtp_extensions, current_streams, video.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001952 return false;
1953 }
1954
zhihuang1c378ed2017-08-17 14:10:50 -07001955 video->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001956
1957 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1958 SetMediaProtocol(secure_transport, video.get());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001959
zhihuang1c378ed2017-08-17 14:10:50 -07001960 video->set_direction(
1961 media_description_options.direction.ToMediaContentDirection());
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001962
zhihuang1c378ed2017-08-17 14:10:50 -07001963 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
1964 media_description_options.stopped, video.release());
1965 if (!AddTransportOffer(media_description_options.mid,
1966 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001967 current_description, desc)) {
1968 return false;
1969 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001970 return true;
1971}
1972
1973bool MediaSessionDescriptionFactory::AddDataContentForOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07001974 const MediaDescriptionOptions& media_description_options,
1975 const MediaSessionOptions& session_options,
1976 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001977 const SessionDescription* current_description,
zhihuang1c378ed2017-08-17 14:10:50 -07001978 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001979 StreamParamsVec* current_streams,
1980 SessionDescription* desc) const {
1981 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
1982
kwiberg31022942016-03-11 14:18:21 -08001983 std::unique_ptr<DataContentDescription> data(new DataContentDescription());
zhihuang1c378ed2017-08-17 14:10:50 -07001984 bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
1985 // If the DataChannel type is not specified, use the DataChannel type in
1986 // the current description.
1987 if (session_options.data_channel_type == DCT_NONE && current_content) {
1988 is_sctp = (static_cast<const DataContentDescription*>(
1989 current_content->description)
1990 ->protocol() == kMediaProtocolSctp);
1991 }
deadbeef44f08192015-12-15 16:20:09 -08001992
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001993 cricket::SecurePolicy sdes_policy =
zhihuang1c378ed2017-08-17 14:10:50 -07001994 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
1995 : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001996 std::vector<std::string> crypto_suites;
1997 if (is_sctp) {
1998 // SDES doesn't make sense for SCTP, so we disable it, and we only
1999 // get SDES crypto suites for RTP-based data channels.
2000 sdes_policy = cricket::SEC_DISABLED;
2001 // Unlike SetMediaProtocol below, we need to set the protocol
2002 // before we call CreateMediaContentOffer. Otherwise,
2003 // CreateMediaContentOffer won't know this is SCTP and will
2004 // generate SSRCs rather than SIDs.
deadbeef8b7e9ad2017-05-25 09:38:55 -07002005 // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
2006 // it's safe to do so. Older versions of webrtc would reject these
2007 // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002008 data->set_protocol(
2009 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
2010 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002011 GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
deadbeef7914b8c2017-04-21 03:23:33 -07002012 &crypto_suites);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002013 }
2014
zhihuang1c378ed2017-08-17 14:10:50 -07002015 // Even SCTP uses a "codec".
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002016 if (!CreateMediaContentOffer(
zhihuang1c378ed2017-08-17 14:10:50 -07002017 media_description_options.sender_options, session_options,
2018 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
2019 RtpHeaderExtensions(), current_streams, data.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002020 return false;
2021 }
2022
2023 if (is_sctp) {
zhihuang1c378ed2017-08-17 14:10:50 -07002024 desc->AddContent(media_description_options.mid, NS_JINGLE_DRAFT_SCTP,
2025 data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002026 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002027 data->set_bandwidth(kDataMaxBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002028 SetMediaProtocol(secure_transport, data.get());
zhihuang1c378ed2017-08-17 14:10:50 -07002029 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
2030 media_description_options.stopped, data.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002031 }
zhihuang1c378ed2017-08-17 14:10:50 -07002032 if (!AddTransportOffer(media_description_options.mid,
2033 media_description_options.transport_options,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002034 current_description, desc)) {
2035 return false;
2036 }
2037 return true;
2038}
2039
zhihuang1c378ed2017-08-17 14:10:50 -07002040// |audio_codecs| = set of all possible codecs that can be used, with correct
2041// payload type mappings
2042//
2043// |supported_audio_codecs| = set of codecs that are supported for the direction
2044// of this m= section
2045//
2046// acd->codecs() = set of previously negotiated codecs for this m= section
2047//
2048// The payload types should come from audio_codecs, but the order should come
2049// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
2050// change existing codec priority, and that new codecs are added with the right
2051// priority.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002052bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002053 const MediaDescriptionOptions& media_description_options,
2054 const MediaSessionOptions& session_options,
2055 const ContentInfo* offer_content,
2056 const SessionDescription* offer_description,
2057 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002058 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002059 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002060 const AudioCodecs& audio_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002061 StreamParamsVec* current_streams,
2062 SessionDescription* answer) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002063 const AudioContentDescription* offer_audio_description =
2064 static_cast<const AudioContentDescription*>(offer_content->description);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002065
deadbeefb7892532017-02-22 19:35:18 -08002066 std::unique_ptr<TransportDescription> audio_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002067 CreateTransportAnswer(media_description_options.mid, offer_description,
2068 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002069 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002070 if (!audio_transport) {
2071 return false;
2072 }
2073
zhihuang1c378ed2017-08-17 14:10:50 -07002074 // Pick codecs based on the requested communications direction in the offer
2075 // and the selected direction in the answer.
2076 // Note these will be filtered one final time in CreateMediaContentAnswer.
2077 auto wants_rtd = media_description_options.direction;
2078 auto offer_rtd = RtpTransceiverDirection::FromMediaContentDirection(
2079 offer_audio_description->direction());
ossu075af922016-06-14 03:29:38 -07002080 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
zhihuang1c378ed2017-08-17 14:10:50 -07002081 AudioCodecs supported_audio_codecs =
2082 GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
2083
2084 AudioCodecs filtered_codecs;
2085 // Add the codecs from current content if exists.
2086 if (current_content) {
2087 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
2088 const AudioContentDescription* acd =
2089 static_cast<const AudioContentDescription*>(
2090 current_content->description);
2091 for (const AudioCodec& codec : acd->codecs()) {
2092 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2093 codec, nullptr)) {
2094 filtered_codecs.push_back(codec);
2095 }
2096 }
2097 }
2098 // Add other supported audio codecs.
2099 AudioCodec found_codec;
2100 for (const AudioCodec& codec : supported_audio_codecs) {
2101 if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
2102 codec, &found_codec) &&
2103 !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
2104 codec, nullptr)) {
2105 // Use the |found_codec| from |audio_codecs| because it has the correctly
2106 // mapped payload type.
2107 filtered_codecs.push_back(found_codec);
2108 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002109 }
2110
zhihuang1c378ed2017-08-17 14:10:50 -07002111 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2112 session_options.bundle_enabled;
kwiberg31022942016-03-11 14:18:21 -08002113 std::unique_ptr<AudioContentDescription> audio_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002114 new AudioContentDescription());
2115 // Do not require or create SDES cryptos if DTLS is used.
2116 cricket::SecurePolicy sdes_policy =
2117 audio_transport->secure() ? cricket::SEC_DISABLED : secure();
2118 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002119 offer_audio_description, media_description_options, session_options,
2120 filtered_codecs, sdes_policy, GetCryptos(current_content),
2121 audio_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2122 current_streams, bundle_enabled, audio_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002123 return false; // Fails the session setup.
2124 }
2125
deadbeefb7892532017-02-22 19:35:18 -08002126 bool secure = bundle_transport ? bundle_transport->description.secure()
2127 : audio_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002128 bool rejected = media_description_options.stopped ||
2129 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002130 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
2131 audio_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002132 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002133 AddTransportAnswer(media_description_options.mid, *(audio_transport.get()),
2134 answer);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002135 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002136 LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
2137 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002138 }
2139
zhihuang1c378ed2017-08-17 14:10:50 -07002140 answer->AddContent(media_description_options.mid, offer_content->type,
2141 rejected, audio_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002142 return true;
2143}
2144
2145bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002146 const MediaDescriptionOptions& media_description_options,
2147 const MediaSessionOptions& session_options,
2148 const ContentInfo* offer_content,
2149 const SessionDescription* offer_description,
2150 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002151 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002152 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002153 const VideoCodecs& video_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002154 StreamParamsVec* current_streams,
2155 SessionDescription* answer) const {
zhihuang1c378ed2017-08-17 14:10:50 -07002156 const VideoContentDescription* offer_video_description =
2157 static_cast<const VideoContentDescription*>(offer_content->description);
2158
deadbeefb7892532017-02-22 19:35:18 -08002159 std::unique_ptr<TransportDescription> video_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002160 CreateTransportAnswer(media_description_options.mid, offer_description,
2161 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002162 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002163 if (!video_transport) {
2164 return false;
2165 }
2166
zhihuang1c378ed2017-08-17 14:10:50 -07002167 VideoCodecs filtered_codecs;
2168 // Add the codecs from current content if exists.
2169 if (current_content) {
2170 RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
2171 const VideoContentDescription* vcd =
2172 static_cast<const VideoContentDescription*>(
2173 current_content->description);
2174 for (const VideoCodec& codec : vcd->codecs()) {
2175 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2176 nullptr)) {
2177 filtered_codecs.push_back(codec);
2178 }
2179 }
2180 }
2181 // Add other supported video codecs.
2182 VideoCodec found_codec;
2183 for (const VideoCodec& codec : video_codecs_) {
2184 if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
2185 &found_codec) &&
2186 !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
2187 nullptr)) {
2188 // Use the |found_codec| from |video_codecs| because it has the correctly
2189 // mapped payload type.
2190 filtered_codecs.push_back(found_codec);
2191 }
2192 }
2193
2194 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2195 session_options.bundle_enabled;
2196
kwiberg31022942016-03-11 14:18:21 -08002197 std::unique_ptr<VideoContentDescription> video_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002198 new VideoContentDescription());
2199 // Do not require or create SDES cryptos if DTLS is used.
2200 cricket::SecurePolicy sdes_policy =
2201 video_transport->secure() ? cricket::SEC_DISABLED : secure();
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002202 if (!CreateMediaContentAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002203 offer_video_description, media_description_options, session_options,
2204 filtered_codecs, sdes_policy, GetCryptos(current_content),
2205 video_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
2206 current_streams, bundle_enabled, video_answer.get())) {
2207 return false; // Failed the sessin setup.
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002208 }
deadbeefb7892532017-02-22 19:35:18 -08002209 bool secure = bundle_transport ? bundle_transport->description.secure()
2210 : video_transport->secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002211 bool rejected = media_description_options.stopped ||
2212 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002213 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
2214 video_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002215 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002216 if (!AddTransportAnswer(media_description_options.mid,
2217 *(video_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002218 return false;
2219 }
zhihuang1c378ed2017-08-17 14:10:50 -07002220 video_answer->set_bandwidth(kAutoBandwidth);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002221 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07002222 LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
2223 << "' being rejected in answer.";
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002224 }
zhihuang1c378ed2017-08-17 14:10:50 -07002225 answer->AddContent(media_description_options.mid, offer_content->type,
2226 rejected, video_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002227 return true;
2228}
2229
2230bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
zhihuang1c378ed2017-08-17 14:10:50 -07002231 const MediaDescriptionOptions& media_description_options,
2232 const MediaSessionOptions& session_options,
2233 const ContentInfo* offer_content,
2234 const SessionDescription* offer_description,
2235 const ContentInfo* current_content,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002236 const SessionDescription* current_description,
deadbeefb7892532017-02-22 19:35:18 -08002237 const TransportInfo* bundle_transport,
zhihuang1c378ed2017-08-17 14:10:50 -07002238 const DataCodecs& data_codecs,
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002239 StreamParamsVec* current_streams,
2240 SessionDescription* answer) const {
deadbeefb7892532017-02-22 19:35:18 -08002241 std::unique_ptr<TransportDescription> data_transport(
zhihuang1c378ed2017-08-17 14:10:50 -07002242 CreateTransportAnswer(media_description_options.mid, offer_description,
2243 media_description_options.transport_options,
deadbeefb7892532017-02-22 19:35:18 -08002244 current_description, bundle_transport != nullptr));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002245 if (!data_transport) {
2246 return false;
2247 }
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002248
kwiberg31022942016-03-11 14:18:21 -08002249 std::unique_ptr<DataContentDescription> data_answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002250 new DataContentDescription());
2251 // Do not require or create SDES cryptos if DTLS is used.
2252 cricket::SecurePolicy sdes_policy =
2253 data_transport->secure() ? cricket::SEC_DISABLED : secure();
zhihuang1c378ed2017-08-17 14:10:50 -07002254 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
2255 session_options.bundle_enabled;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002256 if (!CreateMediaContentAnswer(
2257 static_cast<const DataContentDescription*>(
zhihuang1c378ed2017-08-17 14:10:50 -07002258 offer_content->description),
2259 media_description_options, session_options, data_codecs, sdes_policy,
2260 GetCryptos(current_content), RtpHeaderExtensions(),
2261 enable_encrypted_rtp_header_extensions_, current_streams,
2262 bundle_enabled, data_answer.get())) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002263 return false; // Fails the session setup.
2264 }
2265
zstein4b2e0822017-02-17 19:48:38 -08002266 // Respond with sctpmap if the offer uses sctpmap.
2267 const DataContentDescription* offer_data_description =
zhihuang1c378ed2017-08-17 14:10:50 -07002268 static_cast<const DataContentDescription*>(offer_content->description);
zstein4b2e0822017-02-17 19:48:38 -08002269 bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
2270 data_answer->set_use_sctpmap(offer_uses_sctpmap);
2271
deadbeefb7892532017-02-22 19:35:18 -08002272 bool secure = bundle_transport ? bundle_transport->description.secure()
2273 : data_transport->secure();
2274
zhihuang1c378ed2017-08-17 14:10:50 -07002275 bool rejected = session_options.data_channel_type == DCT_NONE ||
2276 media_description_options.stopped ||
2277 offer_content->rejected ||
deadbeefb7892532017-02-22 19:35:18 -08002278 !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
2279 data_answer->protocol(), secure);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002280 if (!rejected) {
zhihuang1c378ed2017-08-17 14:10:50 -07002281 data_answer->set_bandwidth(kDataMaxBandwidth);
2282 if (!AddTransportAnswer(media_description_options.mid,
2283 *(data_transport.get()), answer)) {
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002284 return false;
2285 }
2286 } else {
2287 // RFC 3264
2288 // The answer MUST contain the same number of m-lines as the offer.
2289 LOG(LS_INFO) << "Data is not supported in the answer.";
2290 }
zhihuang1c378ed2017-08-17 14:10:50 -07002291 answer->AddContent(media_description_options.mid, offer_content->type,
2292 rejected, data_answer.release());
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00002293 return true;
2294}
2295
zhihuang1c378ed2017-08-17 14:10:50 -07002296void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
2297 audio_sendrecv_codecs_.clear();
2298 all_audio_codecs_.clear();
2299 // Compute the audio codecs union.
2300 for (const AudioCodec& send : audio_send_codecs_) {
2301 all_audio_codecs_.push_back(send);
2302 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
2303 send, nullptr)) {
2304 // It doesn't make sense to have an RTX codec we support sending but not
2305 // receiving.
2306 RTC_DCHECK(!IsRtxCodec(send));
2307 }
2308 }
2309 for (const AudioCodec& recv : audio_recv_codecs_) {
2310 if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
2311 recv, nullptr)) {
2312 all_audio_codecs_.push_back(recv);
2313 }
2314 }
2315 // Use NegotiateCodecs to merge our codec lists, since the operation is
2316 // essentially the same. Put send_codecs as the offered_codecs, which is the
2317 // order we'd like to follow. The reasoning is that encoding is usually more
2318 // expensive than decoding, and prioritizing a codec in the send list probably
2319 // means it's a codec we can handle efficiently.
2320 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
2321 &audio_sendrecv_codecs_);
2322}
2323
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324bool IsMediaContent(const ContentInfo* content) {
2325 return (content &&
2326 (content->type == NS_JINGLE_RTP ||
2327 content->type == NS_JINGLE_DRAFT_SCTP));
2328}
2329
2330bool IsAudioContent(const ContentInfo* content) {
2331 return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
2332}
2333
2334bool IsVideoContent(const ContentInfo* content) {
2335 return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
2336}
2337
2338bool IsDataContent(const ContentInfo* content) {
2339 return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
2340}
2341
deadbeef0ed85b22016-02-23 17:24:52 -08002342const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
2343 MediaType media_type) {
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002344 for (const ContentInfo& content : contents) {
2345 if (IsMediaContentOfType(&content, media_type)) {
2346 return &content;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002347 }
2348 }
deadbeef0ed85b22016-02-23 17:24:52 -08002349 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350}
2351
2352const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
2353 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2354}
2355
2356const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
2357 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2358}
2359
2360const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
2361 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2362}
2363
2364static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
2365 MediaType media_type) {
deadbeef0ed85b22016-02-23 17:24:52 -08002366 if (sdesc == nullptr) {
2367 return nullptr;
2368 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369
2370 return GetFirstMediaContent(sdesc->contents(), media_type);
2371}
2372
2373const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
2374 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2375}
2376
2377const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
2378 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2379}
2380
2381const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
2382 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2383}
2384
2385const MediaContentDescription* GetFirstMediaContentDescription(
2386 const SessionDescription* sdesc, MediaType media_type) {
2387 const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2388 const ContentDescription* description = content ? content->description : NULL;
2389 return static_cast<const MediaContentDescription*>(description);
2390}
2391
2392const AudioContentDescription* GetFirstAudioContentDescription(
2393 const SessionDescription* sdesc) {
2394 return static_cast<const AudioContentDescription*>(
2395 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2396}
2397
2398const VideoContentDescription* GetFirstVideoContentDescription(
2399 const SessionDescription* sdesc) {
2400 return static_cast<const VideoContentDescription*>(
2401 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2402}
2403
2404const DataContentDescription* GetFirstDataContentDescription(
2405 const SessionDescription* sdesc) {
2406 return static_cast<const DataContentDescription*>(
2407 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2408}
2409
Taylor Brandstetterdc4eb8c2016-05-12 08:14:50 -07002410//
2411// Non-const versions of the above functions.
2412//
2413
2414ContentInfo* GetFirstMediaContent(ContentInfos& contents,
2415 MediaType media_type) {
2416 for (ContentInfo& content : contents) {
2417 if (IsMediaContentOfType(&content, media_type)) {
2418 return &content;
2419 }
2420 }
2421 return nullptr;
2422}
2423
2424ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
2425 return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
2426}
2427
2428ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
2429 return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
2430}
2431
2432ContentInfo* GetFirstDataContent(ContentInfos& contents) {
2433 return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
2434}
2435
2436static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
2437 MediaType media_type) {
2438 if (sdesc == nullptr) {
2439 return nullptr;
2440 }
2441
2442 return GetFirstMediaContent(sdesc->contents(), media_type);
2443}
2444
2445ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
2446 return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2447}
2448
2449ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
2450 return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2451}
2452
2453ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
2454 return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
2455}
2456
2457MediaContentDescription* GetFirstMediaContentDescription(
2458 SessionDescription* sdesc,
2459 MediaType media_type) {
2460 ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
2461 ContentDescription* description = content ? content->description : NULL;
2462 return static_cast<MediaContentDescription*>(description);
2463}
2464
2465AudioContentDescription* GetFirstAudioContentDescription(
2466 SessionDescription* sdesc) {
2467 return static_cast<AudioContentDescription*>(
2468 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
2469}
2470
2471VideoContentDescription* GetFirstVideoContentDescription(
2472 SessionDescription* sdesc) {
2473 return static_cast<VideoContentDescription*>(
2474 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
2475}
2476
2477DataContentDescription* GetFirstDataContentDescription(
2478 SessionDescription* sdesc) {
2479 return static_cast<DataContentDescription*>(
2480 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
2481}
2482
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002483} // namespace cricket