blob: 5d414baac2f89c60df48bfd9d451132eeb7d7b8b [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -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
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/webrtcsession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
pbos@webrtc.org371243d2014-03-07 15:22:04 +000013#include <limits.h>
14
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <algorithm>
deadbeefcbecd352015-09-23 11:50:27 -070016#include <set>
Tommif888bb52015-12-12 01:37:01 +010017#include <utility>
18#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019
kjellandera69d9732016-08-31 07:33:05 -070020#include "webrtc/api/call/audio_sink.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010021#include "webrtc/api/jsepicecandidate.h"
22#include "webrtc/api/jsepsessiondescription.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010023#include "webrtc/api/peerconnectioninterface.h"
24#include "webrtc/api/sctputils.h"
25#include "webrtc/api/webrtcsessiondescriptionfactory.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000026#include "webrtc/base/basictypes.h"
zhihuang9763d562016-08-05 11:14:50 -070027#include "webrtc/base/bind.h"
jbauchac8869e2015-07-03 01:36:14 -070028#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000029#include "webrtc/base/helpers.h"
30#include "webrtc/base/logging.h"
31#include "webrtc/base/stringencode.h"
32#include "webrtc/base/stringutils.h"
ossuf515ab82016-12-07 04:52:58 -080033#include "webrtc/call/call.h"
kjellanderf4752772016-03-02 05:42:30 -080034#include "webrtc/media/base/mediaconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080035#include "webrtc/media/base/videocapturer.h"
pthatcher@webrtc.org40b276e2014-12-12 02:44:30 +000036#include "webrtc/p2p/base/portallocator.h"
stefanc1aeaf02015-10-15 07:26:07 -070037#include "webrtc/p2p/base/transportchannel.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010038#include "webrtc/pc/channel.h"
39#include "webrtc/pc/channelmanager.h"
40#include "webrtc/pc/mediasession.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
zhihuang9763d562016-08-05 11:14:50 -070042#ifdef HAVE_QUIC
43#include "webrtc/p2p/quic/quictransportchannel.h"
44#endif // HAVE_QUIC
45
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046using cricket::ContentInfo;
47using cricket::ContentInfos;
48using cricket::MediaContentDescription;
49using cricket::SessionDescription;
50using cricket::TransportInfo;
51
Guo-wei Shieh3d564c12015-08-19 16:51:15 -070052using cricket::LOCAL_PORT_TYPE;
53using cricket::STUN_PORT_TYPE;
54using cricket::RELAY_PORT_TYPE;
55using cricket::PRFLX_PORT_TYPE;
56
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057namespace webrtc {
58
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059// Error messages
henrike@webrtc.org1e09a712013-07-26 19:17:59 +000060const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE "
61 "is enabled.";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000062const char kCreateChannelFailed[] = "Failed to create channels.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063const char kInvalidCandidates[] = "Description contains invalid candidates.";
64const char kInvalidSdp[] = "Invalid session description.";
65const char kMlineMismatch[] =
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000066 "Offer and answer descriptions m-lines are not matching. Rejecting answer.";
67const char kPushDownTDFailed[] =
68 "Failed to push down transport description:";
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000069const char kSdpWithoutDtlsFingerprint[] =
70 "Called with SDP without DTLS fingerprint.";
71const char kSdpWithoutSdesCrypto[] =
72 "Called with SDP without SDES crypto.";
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +000073const char kSdpWithoutIceUfragPwd[] =
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000074 "Called with SDP without ice-ufrag and ice-pwd.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075const char kSessionError[] = "Session error code: ";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +000076const char kSessionErrorDesc[] = "Session error description: ";
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +000077const char kDtlsSetupFailureRtp[] =
78 "Couldn't set up DTLS-SRTP on RTP channel.";
79const char kDtlsSetupFailureRtcp[] =
80 "Couldn't set up DTLS-SRTP on RTCP channel.";
deadbeefcbecd352015-09-23 11:50:27 -070081const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082
Guo-wei Shieh3d564c12015-08-19 16:51:15 -070083IceCandidatePairType GetIceCandidatePairCounter(
84 const cricket::Candidate& local,
85 const cricket::Candidate& remote) {
86 const auto& l = local.type();
87 const auto& r = remote.type();
88 const auto& host = LOCAL_PORT_TYPE;
89 const auto& srflx = STUN_PORT_TYPE;
90 const auto& relay = RELAY_PORT_TYPE;
91 const auto& prflx = PRFLX_PORT_TYPE;
Guo-wei Shieh3cc834a2015-09-04 15:52:14 -070092 if (l == host && r == host) {
93 bool local_private = IPIsPrivate(local.address().ipaddr());
94 bool remote_private = IPIsPrivate(remote.address().ipaddr());
95 if (local_private) {
96 if (remote_private) {
97 return kIceCandidatePairHostPrivateHostPrivate;
98 } else {
99 return kIceCandidatePairHostPrivateHostPublic;
100 }
101 } else {
102 if (remote_private) {
103 return kIceCandidatePairHostPublicHostPrivate;
104 } else {
105 return kIceCandidatePairHostPublicHostPublic;
106 }
107 }
108 }
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700109 if (l == host && r == srflx)
110 return kIceCandidatePairHostSrflx;
111 if (l == host && r == relay)
112 return kIceCandidatePairHostRelay;
113 if (l == host && r == prflx)
114 return kIceCandidatePairHostPrflx;
115 if (l == srflx && r == host)
116 return kIceCandidatePairSrflxHost;
117 if (l == srflx && r == srflx)
118 return kIceCandidatePairSrflxSrflx;
119 if (l == srflx && r == relay)
120 return kIceCandidatePairSrflxRelay;
121 if (l == srflx && r == prflx)
122 return kIceCandidatePairSrflxPrflx;
123 if (l == relay && r == host)
124 return kIceCandidatePairRelayHost;
125 if (l == relay && r == srflx)
126 return kIceCandidatePairRelaySrflx;
127 if (l == relay && r == relay)
128 return kIceCandidatePairRelayRelay;
129 if (l == relay && r == prflx)
130 return kIceCandidatePairRelayPrflx;
131 if (l == prflx && r == host)
132 return kIceCandidatePairPrflxHost;
133 if (l == prflx && r == srflx)
134 return kIceCandidatePairPrflxSrflx;
135 if (l == prflx && r == relay)
136 return kIceCandidatePairPrflxRelay;
137 return kIceCandidatePairMax;
138}
139
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140// Compares |answer| against |offer|. Comparision is done
141// for number of m-lines in answer against offer. If matches true will be
142// returned otherwise false.
143static bool VerifyMediaDescriptions(
144 const SessionDescription* answer, const SessionDescription* offer) {
145 if (offer->contents().size() != answer->contents().size())
146 return false;
147
148 for (size_t i = 0; i < offer->contents().size(); ++i) {
149 if ((offer->contents()[i].name) != answer->contents()[i].name) {
150 return false;
151 }
wu@webrtc.org4e393072014-04-07 17:04:35 +0000152 const MediaContentDescription* offer_mdesc =
153 static_cast<const MediaContentDescription*>(
154 offer->contents()[i].description);
155 const MediaContentDescription* answer_mdesc =
156 static_cast<const MediaContentDescription*>(
157 answer->contents()[i].description);
158 if (offer_mdesc->type() != answer_mdesc->type()) {
159 return false;
160 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161 }
162 return true;
163}
164
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165// Checks that each non-rejected content has SDES crypto keys or a DTLS
166// fingerprint. Mismatches, such as replying with a DTLS fingerprint to SDES
167// keys, will be caught in Transport negotiation, and backstopped by Channel's
deadbeef7af91dd2016-12-13 11:29:11 -0800168// |srtp_required| check.
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000169static bool VerifyCrypto(const SessionDescription* desc,
170 bool dtls_enabled,
171 std::string* error) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172 const ContentInfos& contents = desc->contents();
173 for (size_t index = 0; index < contents.size(); ++index) {
174 const ContentInfo* cinfo = &contents[index];
175 if (cinfo->rejected) {
176 continue;
177 }
178
179 // If the content isn't rejected, crypto must be present.
180 const MediaContentDescription* media =
181 static_cast<const MediaContentDescription*>(cinfo->description);
182 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name);
183 if (!media || !tinfo) {
184 // Something is not right.
185 LOG(LS_ERROR) << kInvalidSdp;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000186 *error = kInvalidSdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187 return false;
188 }
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000189 if (dtls_enabled) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000190 if (!tinfo->description.identity_fingerprint) {
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000191 LOG(LS_WARNING) <<
192 "Session description must have DTLS fingerprint if DTLS enabled.";
193 *error = kSdpWithoutDtlsFingerprint;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000194 return false;
195 }
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000196 } else {
197 if (media->cryptos().empty()) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000198 LOG(LS_WARNING) <<
199 "Session description must have SDES when DTLS disabled.";
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000200 *error = kSdpWithoutSdesCrypto;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000201 return false;
202 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203 }
204 }
205
206 return true;
207}
208
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000209// Checks that each non-rejected content has ice-ufrag and ice-pwd set.
210static bool VerifyIceUfragPwdPresent(const SessionDescription* desc) {
211 const ContentInfos& contents = desc->contents();
212 for (size_t index = 0; index < contents.size(); ++index) {
213 const ContentInfo* cinfo = &contents[index];
214 if (cinfo->rejected) {
215 continue;
216 }
217
218 // If the content isn't rejected, ice-ufrag and ice-pwd must be present.
219 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name);
220 if (!tinfo) {
221 // Something is not right.
222 LOG(LS_ERROR) << kInvalidSdp;
223 return false;
224 }
225 if (tinfo->description.ice_ufrag.empty() ||
226 tinfo->description.ice_pwd.empty()) {
227 LOG(LS_ERROR) << "Session description must have ice ufrag and pwd.";
228 return false;
229 }
230 }
231 return true;
232}
233
Peter Boström0c4e06b2015-10-07 12:23:21 +0200234static bool GetAudioSsrcByTrackId(const SessionDescription* session_description,
235 const std::string& track_id,
236 uint32_t* ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237 const cricket::ContentInfo* audio_info =
238 cricket::GetFirstAudioContent(session_description);
239 if (!audio_info) {
240 LOG(LS_ERROR) << "Audio not used in this call";
241 return false;
242 }
243
244 const cricket::MediaContentDescription* audio_content =
245 static_cast<const cricket::MediaContentDescription*>(
246 audio_info->description);
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000247 const cricket::StreamParams* stream =
248 cricket::GetStreamByIds(audio_content->streams(), "", track_id);
249 if (!stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250 return false;
251 }
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000252
253 *ssrc = stream->first_ssrc();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 return true;
255}
256
257static bool GetTrackIdBySsrc(const SessionDescription* session_description,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258 uint32_t ssrc,
259 std::string* track_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 ASSERT(track_id != NULL);
261
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 const cricket::ContentInfo* audio_info =
263 cricket::GetFirstAudioContent(session_description);
jiayl@webrtc.orge21cc9a2014-08-28 22:21:34 +0000264 if (audio_info) {
265 const cricket::MediaContentDescription* audio_content =
266 static_cast<const cricket::MediaContentDescription*>(
267 audio_info->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000269 const auto* found =
270 cricket::GetStreamBySsrc(audio_content->streams(), ssrc);
271 if (found) {
272 *track_id = found->id;
jiayl@webrtc.orge21cc9a2014-08-28 22:21:34 +0000273 return true;
274 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 }
276
277 const cricket::ContentInfo* video_info =
278 cricket::GetFirstVideoContent(session_description);
jiayl@webrtc.orge21cc9a2014-08-28 22:21:34 +0000279 if (video_info) {
280 const cricket::MediaContentDescription* video_content =
281 static_cast<const cricket::MediaContentDescription*>(
282 video_info->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283
tommi@webrtc.org586f2ed2015-01-22 23:00:41 +0000284 const auto* found =
285 cricket::GetStreamBySsrc(video_content->streams(), ssrc);
286 if (found) {
287 *track_id = found->id;
jiayl@webrtc.orge21cc9a2014-08-28 22:21:34 +0000288 return true;
289 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290 }
291 return false;
292}
293
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000294static bool BadSdp(const std::string& source,
295 const std::string& type,
296 const std::string& reason,
297 std::string* err_desc) {
298 std::ostringstream desc;
deadbeefd59daf82015-10-14 15:02:44 -0700299 desc << "Failed to set " << source;
300 if (!type.empty()) {
301 desc << " " << type;
302 }
303 desc << " sdp: " << reason;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000304
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 if (err_desc) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000306 *err_desc = desc.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 }
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000308 LOG(LS_ERROR) << desc.str();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309 return false;
310}
311
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312static bool BadSdp(cricket::ContentSource source,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000313 const std::string& type,
314 const std::string& reason,
315 std::string* err_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000316 if (source == cricket::CS_LOCAL) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000317 return BadSdp("local", type, reason, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000318 } else {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000319 return BadSdp("remote", type, reason, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 }
321}
322
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000323static bool BadLocalSdp(const std::string& type,
324 const std::string& reason,
325 std::string* err_desc) {
326 return BadSdp(cricket::CS_LOCAL, type, reason, err_desc);
327}
328
329static bool BadRemoteSdp(const std::string& type,
330 const std::string& reason,
331 std::string* err_desc) {
332 return BadSdp(cricket::CS_REMOTE, type, reason, err_desc);
333}
334
335static bool BadOfferSdp(cricket::ContentSource source,
336 const std::string& reason,
337 std::string* err_desc) {
338 return BadSdp(source, SessionDescriptionInterface::kOffer, reason, err_desc);
339}
340
341static bool BadPranswerSdp(cricket::ContentSource source,
342 const std::string& reason,
343 std::string* err_desc) {
344 return BadSdp(source, SessionDescriptionInterface::kPrAnswer,
345 reason, err_desc);
346}
347
348static bool BadAnswerSdp(cricket::ContentSource source,
349 const std::string& reason,
350 std::string* err_desc) {
351 return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352}
353
deadbeefd59daf82015-10-14 15:02:44 -0700354#define GET_STRING_OF_STATE(state) \
355 case webrtc::WebRtcSession::state: \
356 result = #state; \
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 break;
358
deadbeefd59daf82015-10-14 15:02:44 -0700359static std::string GetStateString(webrtc::WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000360 std::string result;
361 switch (state) {
362 GET_STRING_OF_STATE(STATE_INIT)
deadbeefd59daf82015-10-14 15:02:44 -0700363 GET_STRING_OF_STATE(STATE_SENTOFFER)
364 GET_STRING_OF_STATE(STATE_RECEIVEDOFFER)
365 GET_STRING_OF_STATE(STATE_SENTPRANSWER)
366 GET_STRING_OF_STATE(STATE_RECEIVEDPRANSWER)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 GET_STRING_OF_STATE(STATE_INPROGRESS)
deadbeefd59daf82015-10-14 15:02:44 -0700368 GET_STRING_OF_STATE(STATE_CLOSED)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369 default:
370 ASSERT(false);
371 break;
372 }
373 return result;
374}
375
deadbeefd59daf82015-10-14 15:02:44 -0700376#define GET_STRING_OF_ERROR_CODE(err) \
377 case webrtc::WebRtcSession::err: \
378 result = #err; \
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379 break;
380
deadbeefd59daf82015-10-14 15:02:44 -0700381static std::string GetErrorCodeString(webrtc::WebRtcSession::Error err) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 std::string result;
383 switch (err) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000384 GET_STRING_OF_ERROR_CODE(ERROR_NONE)
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000385 GET_STRING_OF_ERROR_CODE(ERROR_CONTENT)
386 GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 default:
deadbeefd59daf82015-10-14 15:02:44 -0700388 RTC_DCHECK(false);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389 break;
390 }
391 return result;
392}
393
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000394static std::string MakeErrorString(const std::string& error,
395 const std::string& desc) {
396 std::ostringstream ret;
397 ret << error << " " << desc;
398 return ret.str();
399}
400
401static std::string MakeTdErrorString(const std::string& desc) {
402 return MakeErrorString(kPushDownTDFailed, desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403}
404
deadbeef0ed85b22016-02-23 17:24:52 -0800405// Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
406bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
407 const SessionDescriptionInterface* new_desc,
408 const std::string& content_name) {
409 if (!old_desc) {
honghaiz503726c2015-07-31 12:37:38 -0700410 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 }
deadbeef0ed85b22016-02-23 17:24:52 -0800412 const SessionDescription* new_sd = new_desc->description();
413 const SessionDescription* old_sd = old_desc->description();
414 const ContentInfo* cinfo = new_sd->GetContentByName(content_name);
415 if (!cinfo || cinfo->rejected) {
416 return false;
417 }
418 // If the content isn't rejected, check if ufrag and password has changed.
419 const cricket::TransportDescription* new_transport_desc =
420 new_sd->GetTransportDescriptionByName(content_name);
421 const cricket::TransportDescription* old_transport_desc =
422 old_sd->GetTransportDescriptionByName(content_name);
423 if (!new_transport_desc || !old_transport_desc) {
424 // No transport description exists. This is not an ICE restart.
425 return false;
426 }
427 if (cricket::IceCredentialsChanged(
428 old_transport_desc->ice_ufrag, old_transport_desc->ice_pwd,
429 new_transport_desc->ice_ufrag, new_transport_desc->ice_pwd)) {
430 LOG(LS_INFO) << "Remote peer requests ICE restart for " << content_name
431 << ".";
432 return true;
433 }
434 return false;
435}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436
zhihuang29ff8442016-07-27 11:07:25 -0700437WebRtcSession::WebRtcSession(
438 webrtc::MediaControllerInterface* media_controller,
439 rtc::Thread* network_thread,
440 rtc::Thread* worker_thread,
441 rtc::Thread* signaling_thread,
442 cricket::PortAllocator* port_allocator,
443 std::unique_ptr<cricket::TransportController> transport_controller)
zhihuang9763d562016-08-05 11:14:50 -0700444 : network_thread_(network_thread),
445 worker_thread_(worker_thread),
danilchape9021a32016-05-17 01:52:02 -0700446 signaling_thread_(signaling_thread),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000447 // RFC 3264: The numeric value of the session id and version in the
448 // o line MUST be representable with a "64 bit signed integer".
449 // Due to this constraint session id |sid_| is max limited to LLONG_MAX.
deadbeefd59daf82015-10-14 15:02:44 -0700450 sid_(rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX)),
zhihuang29ff8442016-07-27 11:07:25 -0700451 transport_controller_(std::move(transport_controller)),
stefanc1aeaf02015-10-15 07:26:07 -0700452 media_controller_(media_controller),
453 channel_manager_(media_controller_->channel_manager()),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 ice_observer_(NULL),
455 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew),
Peter Thatcher54360512015-07-08 11:08:35 -0700456 ice_connection_receiving_(true),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 older_version_remote_peer_(false),
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000458 dtls_enabled_(false),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459 data_channel_type_(cricket::DCT_NONE),
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +0000460 metrics_observer_(NULL) {
deadbeefd59daf82015-10-14 15:02:44 -0700461 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
462 transport_controller_->SignalConnectionState.connect(
deadbeefcbecd352015-09-23 11:50:27 -0700463 this, &WebRtcSession::OnTransportControllerConnectionState);
deadbeefd59daf82015-10-14 15:02:44 -0700464 transport_controller_->SignalReceiving.connect(
deadbeefcbecd352015-09-23 11:50:27 -0700465 this, &WebRtcSession::OnTransportControllerReceiving);
deadbeefd59daf82015-10-14 15:02:44 -0700466 transport_controller_->SignalGatheringState.connect(
deadbeefcbecd352015-09-23 11:50:27 -0700467 this, &WebRtcSession::OnTransportControllerGatheringState);
deadbeefd59daf82015-10-14 15:02:44 -0700468 transport_controller_->SignalCandidatesGathered.connect(
deadbeefcbecd352015-09-23 11:50:27 -0700469 this, &WebRtcSession::OnTransportControllerCandidatesGathered);
Honghai Zhang7fb69db2016-03-14 11:59:18 -0700470 transport_controller_->SignalCandidatesRemoved.connect(
471 this, &WebRtcSession::OnTransportControllerCandidatesRemoved);
zhihuangd82eee02016-08-26 11:25:05 -0700472 transport_controller_->SignalDtlsHandshakeError.connect(
473 this, &WebRtcSession::OnDtlsHandshakeError);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474}
475
476WebRtcSession::~WebRtcSession() {
tommi0f620f42015-07-09 03:25:02 -0700477 ASSERT(signaling_thread()->IsCurrent());
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +0000478 // Destroy video_channel_ first since it may have a pointer to the
479 // voice_channel_.
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +0000480 if (video_channel_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 SignalVideoChannelDestroyed();
482 channel_manager_->DestroyVideoChannel(video_channel_.release());
483 }
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +0000484 if (voice_channel_) {
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +0000485 SignalVoiceChannelDestroyed();
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200486 channel_manager_->DestroyVoiceChannel(voice_channel_.release());
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +0000487 }
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +0000488 if (data_channel_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489 SignalDataChannelDestroyed();
490 channel_manager_->DestroyDataChannel(data_channel_.release());
491 }
zhihuang9763d562016-08-05 11:14:50 -0700492#ifdef HAVE_QUIC
493 if (quic_data_transport_) {
494 quic_data_transport_.reset();
495 }
496#endif
deadbeef057ecf02016-01-20 14:30:43 -0800497 SignalDestroyed();
deadbeefd59daf82015-10-14 15:02:44 -0700498
499 LOG(LS_INFO) << "Session: " << id() << " is destroyed.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500}
501
wu@webrtc.org91053e72013-08-10 07:18:04 +0000502bool WebRtcSession::Initialize(
wu@webrtc.org97077a32013-10-25 21:18:33 +0000503 const PeerConnectionFactoryInterface::Options& options,
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200504 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
Henrik Lundin64dad832015-05-11 12:44:23 +0200505 const PeerConnectionInterface::RTCConfiguration& rtc_configuration) {
506 bundle_policy_ = rtc_configuration.bundle_policy;
Peter Thatcheraf55ccc2015-05-21 07:48:41 -0700507 rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy;
deadbeefd59daf82015-10-14 15:02:44 -0700508 transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version);
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000509
Henrik Boström87713d02015-08-25 09:53:21 +0200510 // Obtain a certificate from RTCConfiguration if any were provided (optional).
511 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
512 if (!rtc_configuration.certificates.empty()) {
513 // TODO(hbos,torbjorng): Decide on certificate-selection strategy instead of
514 // just picking the first one. The decision should be made based on the DTLS
515 // handshake. The DTLS negotiations need to know about all certificates.
516 certificate = rtc_configuration.certificates[0];
517 }
518
honghaiz1f429e32015-09-28 07:57:34 -0700519 SetIceConfig(ParseIceConfig(rtc_configuration));
honghaiz4edc39c2015-09-01 09:53:56 -0700520
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000521 if (options.disable_encryption) {
522 dtls_enabled_ = false;
523 } else {
Henrik Boström87713d02015-08-25 09:53:21 +0200524 // Enable DTLS by default if we have an identity store or a certificate.
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200525 dtls_enabled_ = (cert_generator || certificate);
htaa2a49d92016-03-04 02:51:39 -0800526 // |rtc_configuration| can override the default |dtls_enabled_| value.
527 if (rtc_configuration.enable_dtls_srtp) {
528 dtls_enabled_ = *(rtc_configuration.enable_dtls_srtp);
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000529 }
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000530 }
531
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 // Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000533 // It takes precendence over the disable_sctp_data_channels
534 // PeerConnectionFactoryInterface::Options.
htaa2a49d92016-03-04 02:51:39 -0800535 if (rtc_configuration.enable_rtp_data_channel) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 data_channel_type_ = cricket::DCT_RTP;
zhihuang9763d562016-08-05 11:14:50 -0700537 }
538#ifdef HAVE_QUIC
539 else if (rtc_configuration.enable_quic) {
540 // Use QUIC instead of DTLS when |enable_quic| is true.
541 data_channel_type_ = cricket::DCT_QUIC;
542 transport_controller_->use_quic();
543 if (dtls_enabled_) {
544 LOG(LS_INFO) << "Using QUIC instead of DTLS";
545 }
546 quic_data_transport_.reset(
547 new QuicDataTransport(signaling_thread(), worker_thread(),
548 network_thread(), transport_controller_.get()));
549 }
550#endif // HAVE_QUIC
551 else {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000552 // DTLS has to be enabled to use SCTP.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000553 if (!options.disable_sctp_data_channels && dtls_enabled_) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000554 data_channel_type_ = cricket::DCT_SCTP;
555 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557
htaa2a49d92016-03-04 02:51:39 -0800558 video_options_.screencast_min_bitrate_kbps =
559 rtc_configuration.screencast_min_bitrate;
560 audio_options_.combined_audio_video_bwe =
561 rtc_configuration.combined_audio_video_bwe;
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +0000562
kwiberg102c6a62015-10-30 02:47:38 -0700563 audio_options_.audio_jitter_buffer_max_packets =
Karl Wibergbe579832015-11-10 22:34:18 +0100564 rtc::Optional<int>(rtc_configuration.audio_jitter_buffer_max_packets);
Henrik Lundin64dad832015-05-11 12:44:23 +0200565
Karl Wibergbe579832015-11-10 22:34:18 +0100566 audio_options_.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(
567 rtc_configuration.audio_jitter_buffer_fast_accelerate);
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200568
Henrik Boström87713d02015-08-25 09:53:21 +0200569 if (!dtls_enabled_) {
570 // Construct with DTLS disabled.
571 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200572 signaling_thread(), channel_manager_, this, id(),
573 std::unique_ptr<rtc::RTCCertificateGeneratorInterface>()));
Henrik Boström87713d02015-08-25 09:53:21 +0200574 } else {
575 // Construct with DTLS enabled.
576 if (!certificate) {
Henrik Boström87713d02015-08-25 09:53:21 +0200577 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200578 signaling_thread(), channel_manager_, this, id(),
579 std::move(cert_generator)));
Henrik Boström87713d02015-08-25 09:53:21 +0200580 } else {
581 // Use the already generated certificate.
582 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200583 signaling_thread(), channel_manager_, this, id(), certificate));
Henrik Boström87713d02015-08-25 09:53:21 +0200584 }
585 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000586
Henrik Boströmd8281982015-08-27 10:12:24 +0200587 webrtc_session_desc_factory_->SignalCertificateReady.connect(
588 this, &WebRtcSession::OnCertificateReady);
mallinath@webrtc.org7e809c32013-09-30 18:59:08 +0000589
wu@webrtc.org97077a32013-10-25 21:18:33 +0000590 if (options.disable_encryption) {
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000591 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED);
mallinath@webrtc.org7e809c32013-09-30 18:59:08 +0000592 }
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700593
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 return true;
595}
596
deadbeefd59daf82015-10-14 15:02:44 -0700597void WebRtcSession::Close() {
598 SetState(STATE_CLOSED);
599 RemoveUnusedChannels(nullptr);
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +0000600 ASSERT(!voice_channel_);
601 ASSERT(!video_channel_);
602 ASSERT(!data_channel_);
solenberg03d6d572016-03-01 12:42:03 -0800603 media_controller_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604}
605
deadbeef0ed85b22016-02-23 17:24:52 -0800606cricket::BaseChannel* WebRtcSession::GetChannel(
607 const std::string& content_name) {
608 if (voice_channel() && voice_channel()->content_name() == content_name) {
609 return voice_channel();
610 }
611 if (video_channel() && video_channel()->content_name() == content_name) {
612 return video_channel();
613 }
614 if (data_channel() && data_channel()->content_name() == content_name) {
615 return data_channel();
616 }
617 return nullptr;
618}
619
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000620cricket::SecurePolicy WebRtcSession::SdesPolicy() const {
621 return webrtc_session_desc_factory_->SdesPolicy();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622}
623
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800624bool WebRtcSession::GetSslRole(const std::string& transport_name,
625 rtc::SSLRole* role) {
deadbeeffe4a8a42016-12-20 17:56:17 -0800626 if (!local_description() || !remote_description()) {
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000627 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get "
628 << "SSL Role of the session.";
629 return false;
630 }
631
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800632 return transport_controller_->GetSslRole(transport_name, role);
633}
634
635bool WebRtcSession::GetSslRole(const cricket::BaseChannel* channel,
636 rtc::SSLRole* role) {
637 return channel && GetSslRole(channel->transport_name(), role);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000638}
639
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000640void WebRtcSession::CreateOffer(
641 CreateSessionDescriptionObserver* observer,
deadbeefab9b2d12015-10-14 11:33:11 -0700642 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
643 const cricket::MediaSessionOptions& session_options) {
644 webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000645}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646
deadbeefab9b2d12015-10-14 11:33:11 -0700647void WebRtcSession::CreateAnswer(
648 CreateSessionDescriptionObserver* observer,
deadbeefab9b2d12015-10-14 11:33:11 -0700649 const cricket::MediaSessionOptions& session_options) {
htaa2a49d92016-03-04 02:51:39 -0800650 webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651}
652
653bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
654 std::string* err_desc) {
deadbeefcbecd352015-09-23 11:50:27 -0700655 ASSERT(signaling_thread()->IsCurrent());
656
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000657 // Takes the ownership of |desc| regardless of the result.
kwibergd1fe2812016-04-27 06:47:29 -0700658 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000659
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000660 // Validate SDP.
661 if (!ValidateSessionDescription(desc, cricket::CS_LOCAL, err_desc)) {
662 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 }
664
deadbeefd59daf82015-10-14 15:02:44 -0700665 // Update the initial_offerer flag if this session is the initial_offerer.
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000666 Action action = GetAction(desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 if (state() == STATE_INIT && action == kOffer) {
deadbeefd59daf82015-10-14 15:02:44 -0700668 initial_offerer_ = true;
669 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 }
671
deadbeeffe4a8a42016-12-20 17:56:17 -0800672 if (action == kAnswer) {
673 current_local_description_.reset(desc_temp.release());
674 pending_local_description_.reset(nullptr);
675 current_remote_description_.reset(pending_remote_description_.release());
676 } else {
677 pending_local_description_.reset(desc_temp.release());
678 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679
680 // Transport and Media channels will be created only when offer is set.
deadbeeffe4a8a42016-12-20 17:56:17 -0800681 if (action == kOffer && !CreateChannels(local_description()->description())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 // TODO(mallinath) - Handle CreateChannel failure, as new local description
683 // is applied. Restore back to old description.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000684 return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 }
686
deadbeefcbecd352015-09-23 11:50:27 -0700687 // Remove unused channels if MediaContentDescription is rejected.
deadbeeffe4a8a42016-12-20 17:56:17 -0800688 RemoveUnusedChannels(local_description()->description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000690 if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 return false;
692 }
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000693
deadbeeffe4a8a42016-12-20 17:56:17 -0800694 if (remote_description()) {
deadbeefd59daf82015-10-14 15:02:44 -0700695 // Now that we have a local description, we can push down remote candidates.
deadbeeffe4a8a42016-12-20 17:56:17 -0800696 UseCandidatesInSessionDescription(remote_description());
deadbeefcbecd352015-09-23 11:50:27 -0700697 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698
deadbeef0ed85b22016-02-23 17:24:52 -0800699 pending_ice_restarts_.clear();
700
deadbeefd59daf82015-10-14 15:02:44 -0700701 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000702 return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 }
704 return true;
705}
706
707bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
708 std::string* err_desc) {
deadbeefcbecd352015-09-23 11:50:27 -0700709 ASSERT(signaling_thread()->IsCurrent());
710
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000711 // Takes the ownership of |desc| regardless of the result.
kwibergd1fe2812016-04-27 06:47:29 -0700712 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000713
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000714 // Validate SDP.
715 if (!ValidateSessionDescription(desc, cricket::CS_REMOTE, err_desc)) {
716 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 }
718
deadbeeffe4a8a42016-12-20 17:56:17 -0800719 const SessionDescriptionInterface* old_remote_description =
720 remote_description();
721 // Grab ownership of the description being replaced for the remainder of this
722 // method, since it's used below.
723 std::unique_ptr<SessionDescriptionInterface> replaced_remote_description;
724 Action action = GetAction(desc->type());
725 if (action == kAnswer) {
726 replaced_remote_description.reset(
727 pending_remote_description_ ? pending_remote_description_.release()
728 : current_remote_description_.release());
729 current_remote_description_.reset(desc_temp.release());
730 pending_remote_description_.reset(nullptr);
731 current_local_description_.reset(pending_local_description_.release());
732 } else {
733 replaced_remote_description.reset(pending_remote_description_.release());
734 pending_remote_description_.reset(desc_temp.release());
735 }
deadbeefd59daf82015-10-14 15:02:44 -0700736
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 // Transport and Media channels will be created only when offer is set.
738 if (action == kOffer && !CreateChannels(desc->description())) {
739 // TODO(mallinath) - Handle CreateChannel failure, as new local description
740 // is applied. Restore back to old description.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000741 return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 }
743
deadbeefcbecd352015-09-23 11:50:27 -0700744 // Remove unused channels if MediaContentDescription is rejected.
745 RemoveUnusedChannels(desc->description());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746
747 // NOTE: Candidates allocation will be initiated only when SetLocalDescription
748 // is called.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000749 if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 return false;
751 }
752
deadbeeffe4a8a42016-12-20 17:56:17 -0800753 if (local_description() && !UseCandidatesInSessionDescription(desc)) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000754 return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755 }
756
deadbeeffe4a8a42016-12-20 17:56:17 -0800757 if (old_remote_description) {
deadbeef0ed85b22016-02-23 17:24:52 -0800758 for (const cricket::ContentInfo& content :
deadbeeffe4a8a42016-12-20 17:56:17 -0800759 old_remote_description->description()->contents()) {
deadbeef0ed85b22016-02-23 17:24:52 -0800760 // Check if this new SessionDescription contains new ICE ufrag and
761 // password that indicates the remote peer requests an ICE restart.
762 // TODO(deadbeef): When we start storing both the current and pending
763 // remote description, this should reset pending_ice_restarts and compare
764 // against the current description.
deadbeeffe4a8a42016-12-20 17:56:17 -0800765 if (CheckForRemoteIceRestart(old_remote_description, desc,
766 content.name)) {
deadbeef0ed85b22016-02-23 17:24:52 -0800767 if (action == kOffer) {
768 pending_ice_restarts_.insert(content.name);
769 }
770 } else {
771 // We retain all received candidates only if ICE is not restarted.
772 // When ICE is restarted, all previous candidates belong to an old
773 // generation and should not be kept.
774 // TODO(deadbeef): This goes against the W3C spec which says the remote
775 // description should only contain candidates from the last set remote
776 // description plus any candidates added since then. We should remove
777 // this once we're sure it won't break anything.
778 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
deadbeeffe4a8a42016-12-20 17:56:17 -0800779 old_remote_description, content.name, desc);
deadbeef0ed85b22016-02-23 17:24:52 -0800780 }
781 }
honghaiz503726c2015-07-31 12:37:38 -0700782 }
783
deadbeefd59daf82015-10-14 15:02:44 -0700784 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000785 return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 }
jiayl@webrtc.orgdacdd942015-01-23 17:33:34 +0000787
788 // Set the the ICE connection state to connecting since the connection may
789 // become writable with peer reflexive candidates before any remote candidate
790 // is signaled.
791 // TODO(pthatcher): This is a short-term solution for crbug/446908. A real fix
792 // is to have a new signal the indicates a change in checking state from the
793 // transport and expose a new checking() member from transport that can be
794 // read to determine the current checking state. The existing SignalConnecting
795 // actually means "gathering candidates", so cannot be be used here.
796 if (desc->type() != SessionDescriptionInterface::kOffer &&
797 ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew) {
798 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
799 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 return true;
801}
802
deadbeefd59daf82015-10-14 15:02:44 -0700803void WebRtcSession::LogState(State old_state, State new_state) {
804 LOG(LS_INFO) << "Session:" << id()
805 << " Old state:" << GetStateString(old_state)
806 << " New state:" << GetStateString(new_state);
807}
808
809void WebRtcSession::SetState(State state) {
810 ASSERT(signaling_thread_->IsCurrent());
811 if (state != state_) {
812 LogState(state_, state);
813 state_ = state;
814 SignalState(this, state_);
815 }
816}
817
818void WebRtcSession::SetError(Error error, const std::string& error_desc) {
819 ASSERT(signaling_thread_->IsCurrent());
820 if (error != error_) {
821 error_ = error;
822 error_desc_ = error_desc;
823 }
824}
825
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826bool WebRtcSession::UpdateSessionState(
827 Action action, cricket::ContentSource source,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 std::string* err_desc) {
deadbeefcbecd352015-09-23 11:50:27 -0700829 ASSERT(signaling_thread()->IsCurrent());
830
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 // If there's already a pending error then no state transition should happen.
832 // But all call-sites should be verifying this before calling us!
deadbeefd59daf82015-10-14 15:02:44 -0700833 ASSERT(error() == ERROR_NONE);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000834 std::string td_err;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 if (action == kOffer) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000836 if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) {
837 return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 }
deadbeefd59daf82015-10-14 15:02:44 -0700839 SetState(source == cricket::CS_LOCAL ? STATE_SENTOFFER
840 : STATE_RECEIVEDOFFER);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000841 if (!PushdownMediaDescription(cricket::CA_OFFER, source, err_desc)) {
deadbeefd59daf82015-10-14 15:02:44 -0700842 SetError(ERROR_CONTENT, *err_desc);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000843 }
deadbeefd59daf82015-10-14 15:02:44 -0700844 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000845 return BadOfferSdp(source, GetSessionErrorMsg(), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 }
847 } else if (action == kPrAnswer) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000848 if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) {
849 return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 }
851 EnableChannels();
deadbeefd59daf82015-10-14 15:02:44 -0700852 SetState(source == cricket::CS_LOCAL ? STATE_SENTPRANSWER
853 : STATE_RECEIVEDPRANSWER);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000854 if (!PushdownMediaDescription(cricket::CA_PRANSWER, source, err_desc)) {
deadbeefd59daf82015-10-14 15:02:44 -0700855 SetError(ERROR_CONTENT, *err_desc);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000856 }
deadbeefd59daf82015-10-14 15:02:44 -0700857 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000858 return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 }
860 } else if (action == kAnswer) {
deadbeefcbecd352015-09-23 11:50:27 -0700861 const cricket::ContentGroup* local_bundle =
deadbeeffe4a8a42016-12-20 17:56:17 -0800862 local_description()->description()->GetGroupByName(
863 cricket::GROUP_TYPE_BUNDLE);
deadbeefcbecd352015-09-23 11:50:27 -0700864 const cricket::ContentGroup* remote_bundle =
deadbeeffe4a8a42016-12-20 17:56:17 -0800865 remote_description()->description()->GetGroupByName(
866 cricket::GROUP_TYPE_BUNDLE);
deadbeefcbecd352015-09-23 11:50:27 -0700867 if (local_bundle && remote_bundle) {
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800868 // The answerer decides the transport to bundle on.
deadbeefcbecd352015-09-23 11:50:27 -0700869 const cricket::ContentGroup* answer_bundle =
870 (source == cricket::CS_LOCAL ? local_bundle : remote_bundle);
871 if (!EnableBundle(*answer_bundle)) {
872 LOG(LS_WARNING) << "Failed to enable BUNDLE.";
873 return BadAnswerSdp(source, kEnableBundleFailed, err_desc);
874 }
875 }
Taylor Brandstetterf475d362016-01-08 15:35:57 -0800876 // Only push down the transport description after enabling BUNDLE; we don't
877 // want to push down a description on a transport about to be destroyed.
878 if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) {
879 return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc);
880 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 EnableChannels();
deadbeefd59daf82015-10-14 15:02:44 -0700882 SetState(STATE_INPROGRESS);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000883 if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) {
deadbeefd59daf82015-10-14 15:02:44 -0700884 SetError(ERROR_CONTENT, *err_desc);
pthatcher@webrtc.org592470b2015-03-16 21:15:37 +0000885 }
deadbeefd59daf82015-10-14 15:02:44 -0700886 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +0000887 return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888 }
889 }
890 return true;
891}
892
893WebRtcSession::Action WebRtcSession::GetAction(const std::string& type) {
894 if (type == SessionDescriptionInterface::kOffer) {
895 return WebRtcSession::kOffer;
896 } else if (type == SessionDescriptionInterface::kPrAnswer) {
897 return WebRtcSession::kPrAnswer;
898 } else if (type == SessionDescriptionInterface::kAnswer) {
899 return WebRtcSession::kAnswer;
900 }
901 ASSERT(false && "unknown action type");
902 return WebRtcSession::kOffer;
903}
904
deadbeefd59daf82015-10-14 15:02:44 -0700905bool WebRtcSession::PushdownMediaDescription(
906 cricket::ContentAction action,
907 cricket::ContentSource source,
908 std::string* err) {
909 auto set_content = [this, action, source, err](cricket::BaseChannel* ch) {
910 if (!ch) {
911 return true;
912 } else if (source == cricket::CS_LOCAL) {
deadbeeffe4a8a42016-12-20 17:56:17 -0800913 return ch->PushdownLocalDescription(local_description()->description(),
914 action, err);
deadbeefd59daf82015-10-14 15:02:44 -0700915 } else {
deadbeeffe4a8a42016-12-20 17:56:17 -0800916 return ch->PushdownRemoteDescription(remote_description()->description(),
917 action, err);
deadbeefd59daf82015-10-14 15:02:44 -0700918 }
919 };
920
921 return (set_content(voice_channel()) &&
922 set_content(video_channel()) &&
923 set_content(data_channel()));
924}
925
926bool WebRtcSession::PushdownTransportDescription(cricket::ContentSource source,
927 cricket::ContentAction action,
928 std::string* error_desc) {
929 RTC_DCHECK(signaling_thread()->IsCurrent());
930
931 if (source == cricket::CS_LOCAL) {
deadbeeffe4a8a42016-12-20 17:56:17 -0800932 return PushdownLocalTransportDescription(local_description()->description(),
933 action, error_desc);
deadbeefd59daf82015-10-14 15:02:44 -0700934 }
deadbeeffe4a8a42016-12-20 17:56:17 -0800935 return PushdownRemoteTransportDescription(remote_description()->description(),
936 action, error_desc);
deadbeefd59daf82015-10-14 15:02:44 -0700937}
938
939bool WebRtcSession::PushdownLocalTransportDescription(
940 const SessionDescription* sdesc,
941 cricket::ContentAction action,
942 std::string* err) {
943 RTC_DCHECK(signaling_thread()->IsCurrent());
944
945 if (!sdesc) {
946 return false;
947 }
948
949 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
950 if (!transport_controller_->SetLocalTransportDescription(
951 tinfo.content_name, tinfo.description, action, err)) {
952 return false;
953 }
954 }
955
956 return true;
957}
958
959bool WebRtcSession::PushdownRemoteTransportDescription(
960 const SessionDescription* sdesc,
961 cricket::ContentAction action,
962 std::string* err) {
963 RTC_DCHECK(signaling_thread()->IsCurrent());
964
965 if (!sdesc) {
966 return false;
967 }
968
969 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
970 if (!transport_controller_->SetRemoteTransportDescription(
971 tinfo.content_name, tinfo.description, action, err)) {
972 return false;
973 }
974 }
975
976 return true;
977}
978
979bool WebRtcSession::GetTransportDescription(
980 const SessionDescription* description,
981 const std::string& content_name,
982 cricket::TransportDescription* tdesc) {
983 if (!description || !tdesc) {
984 return false;
985 }
986 const TransportInfo* transport_info =
987 description->GetTransportInfoByName(content_name);
988 if (!transport_info) {
989 return false;
990 }
991 *tdesc = transport_info->description;
992 return true;
993}
994
hbosdf6075a2016-12-19 04:58:02 -0800995std::unique_ptr<SessionStats> WebRtcSession::GetStats_s() {
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +0000996 ASSERT(signaling_thread()->IsCurrent());
hbosdf6075a2016-12-19 04:58:02 -0800997 ChannelNamePairs channel_name_pairs;
998 if (voice_channel()) {
999 channel_name_pairs.voice = rtc::Optional<ChannelNamePair>(ChannelNamePair(
1000 voice_channel()->content_name(), voice_channel()->transport_name()));
1001 }
1002 if (video_channel()) {
1003 channel_name_pairs.video = rtc::Optional<ChannelNamePair>(ChannelNamePair(
1004 video_channel()->content_name(), video_channel()->transport_name()));
1005 }
1006 if (data_channel()) {
1007 channel_name_pairs.data = rtc::Optional<ChannelNamePair>(ChannelNamePair(
1008 data_channel()->content_name(), data_channel()->transport_name()));
1009 }
1010 return GetStats(channel_name_pairs);
deadbeefcbecd352015-09-23 11:50:27 -07001011}
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +00001012
hbosdf6075a2016-12-19 04:58:02 -08001013std::unique_ptr<SessionStats> WebRtcSession::GetStats(
1014 const ChannelNamePairs& channel_name_pairs) {
1015 if (network_thread()->IsCurrent()) {
1016 return GetStats_n(channel_name_pairs);
deadbeefcbecd352015-09-23 11:50:27 -07001017 }
hbosdf6075a2016-12-19 04:58:02 -08001018 return network_thread()->Invoke<std::unique_ptr<SessionStats>>(
1019 RTC_FROM_HERE,
1020 rtc::Bind(&WebRtcSession::GetStats_n, this, channel_name_pairs));
deadbeefcbecd352015-09-23 11:50:27 -07001021}
1022
1023bool WebRtcSession::GetLocalCertificate(
1024 const std::string& transport_name,
1025 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
deadbeefd59daf82015-10-14 15:02:44 -07001026 return transport_controller_->GetLocalCertificate(transport_name,
1027 certificate);
deadbeefcbecd352015-09-23 11:50:27 -07001028}
1029
jbauch555604a2016-04-26 03:13:22 -07001030std::unique_ptr<rtc::SSLCertificate> WebRtcSession::GetRemoteSSLCertificate(
kwibergb4d01c42016-04-06 05:15:06 -07001031 const std::string& transport_name) {
kwibergb4d01c42016-04-06 05:15:06 -07001032 return transport_controller_->GetRemoteSSLCertificate(transport_name);
deadbeefcbecd352015-09-23 11:50:27 -07001033}
1034
deadbeefcbecd352015-09-23 11:50:27 -07001035bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
1036 const std::string* first_content_name = bundle.FirstContentName();
1037 if (!first_content_name) {
1038 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
1039 return false;
1040 }
1041 const std::string& transport_name = *first_content_name;
1042 cricket::BaseChannel* first_channel = GetChannel(transport_name);
1043
zhihuang9763d562016-08-05 11:14:50 -07001044#ifdef HAVE_QUIC
1045 if (quic_data_transport_ &&
1046 bundle.HasContentName(quic_data_transport_->content_name()) &&
1047 quic_data_transport_->transport_name() != transport_name) {
1048 LOG(LS_ERROR) << "Unable to BUNDLE " << quic_data_transport_->content_name()
1049 << " on " << transport_name << "with QUIC.";
1050 }
1051#endif
1052
deadbeefcbecd352015-09-23 11:50:27 -07001053 auto maybe_set_transport = [this, bundle, transport_name,
1054 first_channel](cricket::BaseChannel* ch) {
1055 if (!ch || !bundle.HasContentName(ch->content_name())) {
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +00001056 return true;
1057 }
1058
deadbeefcbecd352015-09-23 11:50:27 -07001059 if (ch->transport_name() == transport_name) {
1060 LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name()
1061 << " on " << transport_name << ".";
1062 return true;
deadbeef47ee2f32015-09-22 15:08:23 -07001063 }
torbjornga81a42f2015-09-23 02:16:58 -07001064
deadbeefcbecd352015-09-23 11:50:27 -07001065 if (!ch->SetTransport(transport_name)) {
1066 LOG(LS_WARNING) << "Failed to enable BUNDLE for " << ch->content_name();
1067 return false;
1068 }
1069 LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on "
1070 << transport_name << ".";
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +00001071 return true;
1072 };
1073
deadbeefcbecd352015-09-23 11:50:27 -07001074 if (!maybe_set_transport(voice_channel()) ||
1075 !maybe_set_transport(video_channel()) ||
1076 !maybe_set_transport(data_channel())) {
1077 return false;
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +00001078 }
deadbeefcbecd352015-09-23 11:50:27 -07001079
pthatcher@webrtc.orgc04a97f2015-03-16 19:31:40 +00001080 return true;
1081}
1082
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001083bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) {
deadbeeffe4a8a42016-12-20 17:56:17 -08001084 if (!remote_description()) {
deadbeefd59daf82015-10-14 15:02:44 -07001085 LOG(LS_ERROR) << "ProcessIceMessage: ICE candidates can't be added "
1086 << "without any remote session description.";
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001087 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088 }
1089
1090 if (!candidate) {
deadbeefd59daf82015-10-14 15:02:44 -07001091 LOG(LS_ERROR) << "ProcessIceMessage: Candidate is NULL.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 return false;
1093 }
1094
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001095 bool valid = false;
deadbeefd59daf82015-10-14 15:02:44 -07001096 bool ready = ReadyToUseRemoteCandidate(candidate, NULL, &valid);
1097 if (!valid) {
1098 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099 }
1100
1101 // Add this candidate to the remote session description.
deadbeeffe4a8a42016-12-20 17:56:17 -08001102 if (!mutable_remote_description()->AddCandidate(candidate)) {
deadbeefd59daf82015-10-14 15:02:44 -07001103 LOG(LS_ERROR) << "ProcessIceMessage: Candidate cannot be used.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104 return false;
1105 }
1106
deadbeefd59daf82015-10-14 15:02:44 -07001107 if (ready) {
1108 return UseCandidate(candidate);
1109 } else {
1110 LOG(LS_INFO) << "ProcessIceMessage: Not ready to use candidate.";
1111 return true;
1112 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001113}
1114
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001115bool WebRtcSession::RemoveRemoteIceCandidates(
1116 const std::vector<cricket::Candidate>& candidates) {
deadbeeffe4a8a42016-12-20 17:56:17 -08001117 if (!remote_description()) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001118 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: ICE candidates can't be "
1119 << "removed without any remote session description.";
1120 return false;
1121 }
1122
1123 if (candidates.empty()) {
1124 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: candidates are empty.";
1125 return false;
1126 }
1127
deadbeeffe4a8a42016-12-20 17:56:17 -08001128 size_t number_removed =
1129 mutable_remote_description()->RemoveCandidates(candidates);
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001130 if (number_removed != candidates.size()) {
1131 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: Failed to remove candidates. "
1132 << "Requested " << candidates.size() << " but only "
1133 << number_removed << " are removed.";
1134 }
1135
1136 // Remove the candidates from the transport controller.
1137 std::string error;
1138 bool res = transport_controller_->RemoveRemoteCandidates(candidates, &error);
1139 if (!res && !error.empty()) {
1140 LOG(LS_ERROR) << "Error when removing remote candidates: " << error;
1141 }
1142 return true;
1143}
1144
deadbeefd59daf82015-10-14 15:02:44 -07001145cricket::IceConfig WebRtcSession::ParseIceConfig(
1146 const PeerConnectionInterface::RTCConfiguration& config) const {
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001147 cricket::ContinualGatheringPolicy gathering_policy;
1148 // TODO(honghaiz): Add the third continual gathering policy in
1149 // PeerConnectionInterface and map it to GATHER_CONTINUALLY_AND_RECOVER.
1150 switch (config.continual_gathering_policy) {
1151 case PeerConnectionInterface::GATHER_ONCE:
1152 gathering_policy = cricket::GATHER_ONCE;
1153 break;
1154 case PeerConnectionInterface::GATHER_CONTINUALLY:
1155 gathering_policy = cricket::GATHER_CONTINUALLY;
1156 break;
1157 default:
1158 RTC_DCHECK(false);
1159 gathering_policy = cricket::GATHER_ONCE;
1160 }
deadbeefd59daf82015-10-14 15:02:44 -07001161 cricket::IceConfig ice_config;
Honghai Zhang049fbb12016-03-07 11:13:07 -08001162 ice_config.receiving_timeout = config.ice_connection_receiving_timeout;
guoweis36f01372016-03-02 18:02:40 -08001163 ice_config.prioritize_most_likely_candidate_pairs =
1164 config.prioritize_most_likely_ice_candidate_pairs;
Honghai Zhang381b4212015-12-04 12:24:03 -08001165 ice_config.backup_connection_ping_interval =
1166 config.ice_backup_candidate_pair_ping_interval;
Honghai Zhang5622c5e2016-07-01 13:59:29 -07001167 ice_config.continual_gathering_policy = gathering_policy;
Taylor Brandstettere9851112016-07-01 11:11:13 -07001168 ice_config.presume_writable_when_fully_relayed =
1169 config.presume_writable_when_fully_relayed;
deadbeefd59daf82015-10-14 15:02:44 -07001170 return ice_config;
1171}
1172
1173void WebRtcSession::SetIceConfig(const cricket::IceConfig& config) {
1174 transport_controller_->SetIceConfig(config);
1175}
1176
1177void WebRtcSession::MaybeStartGathering() {
1178 transport_controller_->MaybeStartGathering();
1179}
1180
Peter Boström0c4e06b2015-10-07 12:23:21 +02001181bool WebRtcSession::GetLocalTrackIdBySsrc(uint32_t ssrc,
1182 std::string* track_id) {
deadbeeffe4a8a42016-12-20 17:56:17 -08001183 if (!local_description()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001184 return false;
deadbeefd59daf82015-10-14 15:02:44 -07001185 }
deadbeeffe4a8a42016-12-20 17:56:17 -08001186 return webrtc::GetTrackIdBySsrc(local_description()->description(), ssrc,
1187 track_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188}
1189
Peter Boström0c4e06b2015-10-07 12:23:21 +02001190bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32_t ssrc,
1191 std::string* track_id) {
deadbeeffe4a8a42016-12-20 17:56:17 -08001192 if (!remote_description()) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +00001193 return false;
deadbeefd59daf82015-10-14 15:02:44 -07001194 }
deadbeeffe4a8a42016-12-20 17:56:17 -08001195 return webrtc::GetTrackIdBySsrc(remote_description()->description(), ssrc,
1196 track_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001199std::string WebRtcSession::BadStateErrMsg(State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200 std::ostringstream desc;
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001201 desc << "Called in wrong state: " << GetStateString(state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 return desc.str();
1203}
1204
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205bool WebRtcSession::CanInsertDtmf(const std::string& track_id) {
1206 ASSERT(signaling_thread()->IsCurrent());
1207 if (!voice_channel_) {
1208 LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
1209 return false;
1210 }
Peter Boström0c4e06b2015-10-07 12:23:21 +02001211 uint32_t send_ssrc = 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc
1213 // exists.
deadbeeffe4a8a42016-12-20 17:56:17 -08001214 if (!local_description() ||
1215 !GetAudioSsrcByTrackId(local_description()->description(), track_id,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001216 &send_ssrc)) {
1217 LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id;
1218 return false;
1219 }
1220 return voice_channel_->CanInsertDtmf();
1221}
1222
1223bool WebRtcSession::InsertDtmf(const std::string& track_id,
1224 int code, int duration) {
1225 ASSERT(signaling_thread()->IsCurrent());
1226 if (!voice_channel_) {
1227 LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
1228 return false;
1229 }
Peter Boström0c4e06b2015-10-07 12:23:21 +02001230 uint32_t send_ssrc = 0;
deadbeeffe4a8a42016-12-20 17:56:17 -08001231 if (!VERIFY(local_description() &&
1232 GetAudioSsrcByTrackId(local_description()->description(),
1233 track_id, &send_ssrc))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id;
1235 return false;
1236 }
solenberg1d63dd02015-12-02 12:35:09 -08001237 if (!voice_channel_->InsertDtmf(send_ssrc, code, duration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
1239 return false;
1240 }
1241 return true;
1242}
1243
1244sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() {
deadbeef057ecf02016-01-20 14:30:43 -08001245 return &SignalDestroyed;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246}
1247
wu@webrtc.org78187522013-10-07 23:32:02 +00001248bool WebRtcSession::SendData(const cricket::SendDataParams& params,
jbaucheec21bd2016-03-20 06:15:43 -07001249 const rtc::CopyOnWriteBuffer& payload,
wu@webrtc.org78187522013-10-07 23:32:02 +00001250 cricket::SendDataResult* result) {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001251 if (!data_channel_) {
wu@webrtc.org78187522013-10-07 23:32:02 +00001252 LOG(LS_ERROR) << "SendData called when data_channel_ is NULL.";
1253 return false;
1254 }
1255 return data_channel_->SendData(params, payload, result);
1256}
1257
1258bool WebRtcSession::ConnectDataChannel(DataChannel* webrtc_data_channel) {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001259 if (!data_channel_) {
deadbeefdaf88b12016-10-05 22:29:30 -07001260 // Don't log an error here, because DataChannels are expected to call
1261 // ConnectDataChannel in this state. It's the only way to initially tell
1262 // whether or not the underlying transport is ready.
wu@webrtc.org78187522013-10-07 23:32:02 +00001263 return false;
1264 }
wu@webrtc.org78187522013-10-07 23:32:02 +00001265 data_channel_->SignalReadyToSendData.connect(webrtc_data_channel,
1266 &DataChannel::OnChannelReady);
1267 data_channel_->SignalDataReceived.connect(webrtc_data_channel,
1268 &DataChannel::OnDataReceived);
deadbeefab9b2d12015-10-14 11:33:11 -07001269 data_channel_->SignalStreamClosedRemotely.connect(
1270 webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
wu@webrtc.org78187522013-10-07 23:32:02 +00001271 return true;
1272}
1273
1274void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001275 if (!data_channel_) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001276 LOG(LS_ERROR) << "DisconnectDataChannel called when data_channel_ is NULL.";
1277 return;
1278 }
wu@webrtc.org78187522013-10-07 23:32:02 +00001279 data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
1280 data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
deadbeefab9b2d12015-10-14 11:33:11 -07001281 data_channel_->SignalStreamClosedRemotely.disconnect(webrtc_data_channel);
wu@webrtc.org78187522013-10-07 23:32:02 +00001282}
1283
bemasc@webrtc.org9b5467e2014-12-04 23:16:52 +00001284void WebRtcSession::AddSctpDataStream(int sid) {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001285 if (!data_channel_) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001286 LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL.";
1287 return;
1288 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +00001289 data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid));
1290 data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001291}
1292
bemasc@webrtc.org9b5467e2014-12-04 23:16:52 +00001293void WebRtcSession::RemoveSctpDataStream(int sid) {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001294 if (!data_channel_) {
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001295 LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
1296 << "NULL.";
1297 return;
1298 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +00001299 data_channel_->RemoveRecvStream(sid);
1300 data_channel_->RemoveSendStream(sid);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001301}
1302
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00001303bool WebRtcSession::ReadyToSendData() const {
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001304 return data_channel_ && data_channel_->ready_to_send_data();
wu@webrtc.org07a6fbe2013-11-04 18:41:34 +00001305}
1306
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307cricket::DataChannelType WebRtcSession::data_channel_type() const {
1308 return data_channel_type_;
1309}
1310
deadbeef0ed85b22016-02-23 17:24:52 -08001311bool WebRtcSession::IceRestartPending(const std::string& content_name) const {
1312 return pending_ice_restarts_.find(content_name) !=
1313 pending_ice_restarts_.end();
wu@webrtc.org91053e72013-08-10 07:18:04 +00001314}
1315
deadbeefd1a38b52016-12-10 13:15:33 -08001316void WebRtcSession::SetNeedsIceRestartFlag() {
1317 transport_controller_->SetNeedsIceRestartFlag();
1318}
1319
1320bool WebRtcSession::NeedsIceRestart(const std::string& content_name) const {
1321 return transport_controller_->NeedsIceRestart(content_name);
1322}
1323
Henrik Boströmd8281982015-08-27 10:12:24 +02001324void WebRtcSession::OnCertificateReady(
1325 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
deadbeefd59daf82015-10-14 15:02:44 -07001326 transport_controller_->SetLocalCertificate(certificate);
wu@webrtc.org91053e72013-08-10 07:18:04 +00001327}
1328
Henrik Boströmd8281982015-08-27 10:12:24 +02001329bool WebRtcSession::waiting_for_certificate_for_testing() const {
Henrik Boström87713d02015-08-25 09:53:21 +02001330 return webrtc_session_desc_factory_->waiting_for_certificate_for_testing();
wu@webrtc.org91053e72013-08-10 07:18:04 +00001331}
1332
deadbeefcbecd352015-09-23 11:50:27 -07001333const rtc::scoped_refptr<rtc::RTCCertificate>&
1334WebRtcSession::certificate_for_testing() {
deadbeefd59daf82015-10-14 15:02:44 -07001335 return transport_controller_->certificate_for_testing();
deadbeefcbecd352015-09-23 11:50:27 -07001336}
1337
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338void WebRtcSession::SetIceConnectionState(
1339 PeerConnectionInterface::IceConnectionState state) {
1340 if (ice_connection_state_ == state) {
1341 return;
1342 }
1343
deadbeefcbecd352015-09-23 11:50:27 -07001344 LOG(LS_INFO) << "Changing IceConnectionState " << ice_connection_state_
1345 << " => " << state;
Taylor Brandstetter6aefc632016-05-26 16:08:23 -07001346 RTC_DCHECK(ice_connection_state_ !=
1347 PeerConnectionInterface::kIceConnectionClosed);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001348 ice_connection_state_ = state;
1349 if (ice_observer_) {
1350 ice_observer_->OnIceConnectionChange(ice_connection_state_);
1351 }
1352}
1353
deadbeefcbecd352015-09-23 11:50:27 -07001354void WebRtcSession::OnTransportControllerConnectionState(
1355 cricket::IceConnectionState state) {
1356 switch (state) {
1357 case cricket::kIceConnectionConnecting:
1358 // If the current state is Connected or Completed, then there were
1359 // writable channels but now there are not, so the next state must
1360 // be Disconnected.
1361 // kIceConnectionConnecting is currently used as the default,
1362 // un-connected state by the TransportController, so its only use is
1363 // detecting disconnections.
1364 if (ice_connection_state_ ==
1365 PeerConnectionInterface::kIceConnectionConnected ||
1366 ice_connection_state_ ==
1367 PeerConnectionInterface::kIceConnectionCompleted) {
1368 SetIceConnectionState(
1369 PeerConnectionInterface::kIceConnectionDisconnected);
1370 }
torbjornga81a42f2015-09-23 02:16:58 -07001371 break;
deadbeefcbecd352015-09-23 11:50:27 -07001372 case cricket::kIceConnectionFailed:
1373 SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
1374 break;
1375 case cricket::kIceConnectionConnected:
1376 LOG(LS_INFO) << "Changing to ICE connected state because "
1377 << "all transports are writable.";
1378 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
1379 break;
1380 case cricket::kIceConnectionCompleted:
1381 LOG(LS_INFO) << "Changing to ICE completed state because "
1382 << "all transports are complete.";
1383 if (ice_connection_state_ !=
1384 PeerConnectionInterface::kIceConnectionConnected) {
1385 // If jumping directly from "checking" to "connected",
1386 // signal "connected" first.
1387 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
1388 }
1389 SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
1390 if (metrics_observer_) {
1391 ReportTransportStats();
1392 }
1393 break;
1394 default:
1395 ASSERT(false);
torbjornga81a42f2015-09-23 02:16:58 -07001396 }
deadbeefcbecd352015-09-23 11:50:27 -07001397}
1398
1399void WebRtcSession::OnTransportControllerReceiving(bool receiving) {
Peter Thatcher54360512015-07-08 11:08:35 -07001400 SetIceConnectionReceiving(receiving);
1401}
1402
1403void WebRtcSession::SetIceConnectionReceiving(bool receiving) {
1404 if (ice_connection_receiving_ == receiving) {
1405 return;
1406 }
1407 ice_connection_receiving_ = receiving;
1408 if (ice_observer_) {
1409 ice_observer_->OnIceConnectionReceivingChange(receiving);
1410 }
1411}
1412
deadbeefcbecd352015-09-23 11:50:27 -07001413void WebRtcSession::OnTransportControllerCandidatesGathered(
1414 const std::string& transport_name,
1415 const cricket::Candidates& candidates) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 ASSERT(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001417 int sdp_mline_index;
1418 if (!GetLocalCandidateMediaIndex(transport_name, &sdp_mline_index)) {
1419 LOG(LS_ERROR) << "OnTransportControllerCandidatesGathered: content name "
1420 << transport_name << " not found";
1421 return;
1422 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001423
deadbeefcbecd352015-09-23 11:50:27 -07001424 for (cricket::Candidates::const_iterator citer = candidates.begin();
1425 citer != candidates.end(); ++citer) {
1426 // Use transport_name as the candidate media id.
1427 JsepIceCandidate candidate(transport_name, sdp_mline_index, *citer);
1428 if (ice_observer_) {
1429 ice_observer_->OnIceCandidate(&candidate);
1430 }
deadbeeffe4a8a42016-12-20 17:56:17 -08001431 if (local_description()) {
1432 mutable_local_description()->AddCandidate(&candidate);
deadbeefcbecd352015-09-23 11:50:27 -07001433 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001434 }
1435}
1436
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001437void WebRtcSession::OnTransportControllerCandidatesRemoved(
1438 const std::vector<cricket::Candidate>& candidates) {
1439 ASSERT(signaling_thread()->IsCurrent());
1440 // Sanity check.
1441 for (const cricket::Candidate& candidate : candidates) {
1442 if (candidate.transport_name().empty()) {
1443 LOG(LS_ERROR) << "OnTransportControllerCandidatesRemoved: "
1444 << "empty content name in candidate "
1445 << candidate.ToString();
1446 return;
1447 }
1448 }
1449
deadbeeffe4a8a42016-12-20 17:56:17 -08001450 if (local_description()) {
1451 mutable_local_description()->RemoveCandidates(candidates);
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001452 }
1453 if (ice_observer_) {
1454 ice_observer_->OnIceCandidatesRemoved(candidates);
1455 }
1456}
1457
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001458// Enabling voice and video channel.
1459void WebRtcSession::EnableChannels() {
1460 if (voice_channel_ && !voice_channel_->enabled())
1461 voice_channel_->Enable(true);
1462
1463 if (video_channel_ && !video_channel_->enabled())
1464 video_channel_->Enable(true);
1465
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001466 if (data_channel_ && !data_channel_->enabled())
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001467 data_channel_->Enable(true);
1468}
1469
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470// Returns the media index for a local ice candidate given the content name.
1471bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name,
1472 int* sdp_mline_index) {
deadbeeffe4a8a42016-12-20 17:56:17 -08001473 if (!local_description() || !sdp_mline_index) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001474 return false;
deadbeefd59daf82015-10-14 15:02:44 -07001475 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001476
1477 bool content_found = false;
deadbeeffe4a8a42016-12-20 17:56:17 -08001478 const ContentInfos& contents = local_description()->description()->contents();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001479 for (size_t index = 0; index < contents.size(); ++index) {
1480 if (contents[index].name == content_name) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001481 *sdp_mline_index = static_cast<int>(index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 content_found = true;
1483 break;
1484 }
1485 }
1486 return content_found;
1487}
1488
1489bool WebRtcSession::UseCandidatesInSessionDescription(
1490 const SessionDescriptionInterface* remote_desc) {
deadbeefd59daf82015-10-14 15:02:44 -07001491 if (!remote_desc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 return true;
deadbeefd59daf82015-10-14 15:02:44 -07001493 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 bool ret = true;
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001495
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001496 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) {
1497 const IceCandidateCollection* candidates = remote_desc->candidates(m);
deadbeefd59daf82015-10-14 15:02:44 -07001498 for (size_t n = 0; n < candidates->count(); ++n) {
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001499 const IceCandidateInterface* candidate = candidates->at(n);
1500 bool valid = false;
1501 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) {
1502 if (valid) {
deadbeefd59daf82015-10-14 15:02:44 -07001503 LOG(LS_INFO) << "UseCandidatesInSessionDescription: Not ready to use "
1504 << "candidate.";
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001505 }
1506 continue;
1507 }
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001508 ret = UseCandidate(candidate);
deadbeefd59daf82015-10-14 15:02:44 -07001509 if (!ret) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001510 break;
deadbeefd59daf82015-10-14 15:02:44 -07001511 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512 }
1513 }
1514 return ret;
1515}
1516
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001517bool WebRtcSession::UseCandidate(const IceCandidateInterface* candidate) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index());
deadbeeffe4a8a42016-12-20 17:56:17 -08001519 size_t remote_content_size =
1520 remote_description()->description()->contents().size();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521 if (mediacontent_index >= remote_content_size) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001522 LOG(LS_ERROR) << "UseCandidate: Invalid candidate media index.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001523 return false;
1524 }
1525
1526 cricket::ContentInfo content =
deadbeeffe4a8a42016-12-20 17:56:17 -08001527 remote_description()->description()->contents()[mediacontent_index];
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528 std::vector<cricket::Candidate> candidates;
1529 candidates.push_back(candidate->candidate());
1530 // Invoking BaseSession method to handle remote candidates.
1531 std::string error;
deadbeefd59daf82015-10-14 15:02:44 -07001532 if (transport_controller_->AddRemoteCandidates(content.name, candidates,
1533 &error)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534 // Candidates successfully submitted for checking.
1535 if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew ||
1536 ice_connection_state_ ==
1537 PeerConnectionInterface::kIceConnectionDisconnected) {
1538 // If state is New, then the session has just gotten its first remote ICE
1539 // candidates, so go to Checking.
1540 // If state is Disconnected, the session is re-using old candidates or
1541 // receiving additional ones, so go to Checking.
1542 // If state is Connected, stay Connected.
1543 // TODO(bemasc): If state is Connected, and the new candidates are for a
1544 // newly added transport, then the state actually _should_ move to
1545 // checking. Add a way to distinguish that case.
1546 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
1547 }
1548 // TODO(bemasc): If state is Completed, go back to Connected.
1549 } else {
fischman@webrtc.org4f2bd682014-03-28 18:13:34 +00001550 if (!error.empty()) {
1551 LOG(LS_WARNING) << error;
1552 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553 }
1554 return true;
1555}
1556
deadbeefcbecd352015-09-23 11:50:27 -07001557void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) {
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +00001558 // Destroy video_channel_ first since it may have a pointer to the
1559 // voice_channel_.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 const cricket::ContentInfo* video_info =
1561 cricket::GetFirstVideoContent(desc);
1562 if ((!video_info || video_info->rejected) && video_channel_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 SignalVideoChannelDestroyed();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564 channel_manager_->DestroyVideoChannel(video_channel_.release());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001565 }
1566
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +00001567 const cricket::ContentInfo* voice_info =
1568 cricket::GetFirstAudioContent(desc);
1569 if ((!voice_info || voice_info->rejected) && voice_channel_) {
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +00001570 SignalVoiceChannelDestroyed();
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001571 channel_manager_->DestroyVoiceChannel(voice_channel_.release());
buildbot@webrtc.orgb4c7b092014-08-25 12:11:58 +00001572 }
1573
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 const cricket::ContentInfo* data_info =
1575 cricket::GetFirstDataContent(desc);
zhihuang9763d562016-08-05 11:14:50 -07001576 if (!data_info || data_info->rejected) {
1577 if (data_channel_) {
1578 SignalDataChannelDestroyed();
1579 channel_manager_->DestroyDataChannel(data_channel_.release());
1580 }
1581#ifdef HAVE_QUIC
1582 // Clean up the existing QuicDataTransport and its QuicTransportChannels.
1583 if (quic_data_transport_) {
1584 quic_data_transport_.reset();
1585 }
1586#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 }
1588}
1589
skvlad6c87a672016-05-17 17:49:52 -07001590// Returns the name of the transport channel when BUNDLE is enabled, or nullptr
1591// if the channel is not part of any bundle.
1592const std::string* WebRtcSession::GetBundleTransportName(
1593 const cricket::ContentInfo* content,
1594 const cricket::ContentGroup* bundle) {
1595 if (!bundle) {
1596 return nullptr;
1597 }
1598 const std::string* first_content_name = bundle->FirstContentName();
1599 if (!first_content_name) {
1600 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
1601 return nullptr;
1602 }
1603 if (!bundle->HasContentName(content->name)) {
1604 LOG(LS_WARNING) << content->name << " is not part of any bundle group";
1605 return nullptr;
1606 }
1607 LOG(LS_INFO) << "Bundling " << content->name << " on " << *first_content_name;
1608 return first_content_name;
1609}
1610
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611bool WebRtcSession::CreateChannels(const SessionDescription* desc) {
skvlad6c87a672016-05-17 17:49:52 -07001612 const cricket::ContentGroup* bundle_group = nullptr;
1613 if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle) {
1614 bundle_group = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1615 if (!bundle_group) {
1616 LOG(LS_WARNING) << "max-bundle specified without BUNDLE specified";
1617 return false;
1618 }
1619 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620 // Creating the media channels and transport proxies.
1621 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc);
1622 if (voice && !voice->rejected && !voice_channel_) {
skvlad6c87a672016-05-17 17:49:52 -07001623 if (!CreateVoiceChannel(voice,
1624 GetBundleTransportName(voice, bundle_group))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625 LOG(LS_ERROR) << "Failed to create voice channel.";
1626 return false;
1627 }
1628 }
1629
1630 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc);
1631 if (video && !video->rejected && !video_channel_) {
skvlad6c87a672016-05-17 17:49:52 -07001632 if (!CreateVideoChannel(video,
1633 GetBundleTransportName(video, bundle_group))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 LOG(LS_ERROR) << "Failed to create video channel.";
1635 return false;
1636 }
1637 }
1638
1639 const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc);
1640 if (data_channel_type_ != cricket::DCT_NONE &&
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001641 data && !data->rejected && !data_channel_) {
skvlad6c87a672016-05-17 17:49:52 -07001642 if (!CreateDataChannel(data, GetBundleTransportName(data, bundle_group))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643 LOG(LS_ERROR) << "Failed to create data channel.";
1644 return false;
1645 }
1646 }
1647
1648 return true;
1649}
1650
skvlad6c87a672016-05-17 17:49:52 -07001651bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content,
1652 const std::string* bundle_transport) {
1653 bool require_rtcp_mux =
1654 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1655 bool create_rtcp_transport_channel = !require_rtcp_mux;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656 voice_channel_.reset(channel_manager_->CreateVoiceChannel(
skvlad6c87a672016-05-17 17:49:52 -07001657 media_controller_, transport_controller_.get(), content->name,
deadbeef7af91dd2016-12-13 11:29:11 -08001658 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1659 audio_options_));
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001660 if (!voice_channel_) {
wu@webrtc.orgde305012013-10-31 15:40:38 +00001661 return false;
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001662 }
skvlad6c87a672016-05-17 17:49:52 -07001663 if (require_rtcp_mux) {
1664 voice_channel_->ActivateRtcpMux();
1665 }
wu@webrtc.orgde305012013-10-31 15:40:38 +00001666
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001667 voice_channel_->SignalDtlsSetupFailure.connect(
1668 this, &WebRtcSession::OnDtlsSetupFailure);
deadbeefab9b2d12015-10-14 11:33:11 -07001669
1670 SignalVoiceChannelCreated();
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001671 voice_channel_->SignalSentPacket.connect(this,
1672 &WebRtcSession::OnSentPacket_w);
wu@webrtc.orgde305012013-10-31 15:40:38 +00001673 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001674}
1675
skvlad6c87a672016-05-17 17:49:52 -07001676bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content,
1677 const std::string* bundle_transport) {
1678 bool require_rtcp_mux =
1679 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1680 bool create_rtcp_transport_channel = !require_rtcp_mux;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681 video_channel_.reset(channel_manager_->CreateVideoChannel(
skvlad6c87a672016-05-17 17:49:52 -07001682 media_controller_, transport_controller_.get(), content->name,
deadbeef7af91dd2016-12-13 11:29:11 -08001683 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1684 video_options_));
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001685 if (!video_channel_) {
1686 return false;
1687 }
skvlad6c87a672016-05-17 17:49:52 -07001688 if (require_rtcp_mux) {
1689 video_channel_->ActivateRtcpMux();
1690 }
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001691 video_channel_->SignalDtlsSetupFailure.connect(
1692 this, &WebRtcSession::OnDtlsSetupFailure);
deadbeefab9b2d12015-10-14 11:33:11 -07001693
1694 SignalVideoChannelCreated();
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001695 video_channel_->SignalSentPacket.connect(this,
1696 &WebRtcSession::OnSentPacket_w);
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001697 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698}
1699
skvlad6c87a672016-05-17 17:49:52 -07001700bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content,
1701 const std::string* bundle_transport) {
zhihuang9763d562016-08-05 11:14:50 -07001702#ifdef HAVE_QUIC
1703 if (data_channel_type_ == cricket::DCT_QUIC) {
1704 RTC_DCHECK(transport_controller_->quic());
1705 const std::string transport_name =
1706 bundle_transport ? *bundle_transport : content->name;
1707 quic_data_transport_->SetTransport(transport_name);
1708 return true;
1709 }
1710#endif // HAVE_QUIC
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001711 bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
skvlad6c87a672016-05-17 17:49:52 -07001712 bool require_rtcp_mux =
1713 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1714 bool create_rtcp_transport_channel = !sctp && !require_rtcp_mux;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001715 data_channel_.reset(channel_manager_->CreateDataChannel(
deadbeef7af91dd2016-12-13 11:29:11 -08001716 media_controller_, transport_controller_.get(), content->name,
1717 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1718 data_channel_type_));
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001719 if (!data_channel_) {
wu@webrtc.org91053e72013-08-10 07:18:04 +00001720 return false;
1721 }
skvlad6c87a672016-05-17 17:49:52 -07001722 if (require_rtcp_mux) {
1723 data_channel_->ActivateRtcpMux();
1724 }
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001725
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001726 if (sctp) {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001727 data_channel_->SignalDataReceived.connect(
1728 this, &WebRtcSession::OnDataChannelMessageReceived);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001729 }
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001730
1731 data_channel_->SignalDtlsSetupFailure.connect(
1732 this, &WebRtcSession::OnDtlsSetupFailure);
deadbeefab9b2d12015-10-14 11:33:11 -07001733
1734 SignalDataChannelCreated();
Danil Chapovalov33b01f22016-05-11 19:55:27 +02001735 data_channel_->SignalSentPacket.connect(this, &WebRtcSession::OnSentPacket_w);
wu@webrtc.org91053e72013-08-10 07:18:04 +00001736 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001737}
1738
hbosdf6075a2016-12-19 04:58:02 -08001739std::unique_ptr<SessionStats> WebRtcSession::GetStats_n(
1740 const ChannelNamePairs& channel_name_pairs) {
1741 ASSERT(network_thread()->IsCurrent());
1742 std::unique_ptr<SessionStats> session_stats(new SessionStats());
1743 for (const auto channel_name_pair : { &channel_name_pairs.voice,
1744 &channel_name_pairs.video,
1745 &channel_name_pairs.data }) {
1746 if (*channel_name_pair) {
1747 cricket::TransportStats transport_stats;
1748 if (!transport_controller_->GetStats((*channel_name_pair)->transport_name,
1749 &transport_stats)) {
1750 return nullptr;
1751 }
1752 session_stats->proxy_to_transport[(*channel_name_pair)->content_name] =
1753 (*channel_name_pair)->transport_name;
1754 session_stats->transport_stats[(*channel_name_pair)->transport_name] =
1755 std::move(transport_stats);
1756 }
1757 }
1758 return session_stats;
1759}
1760
pthatcher@webrtc.org4eeef582015-03-16 19:34:23 +00001761void WebRtcSession::OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp) {
deadbeefd59daf82015-10-14 15:02:44 -07001762 SetError(ERROR_TRANSPORT,
1763 rtcp ? kDtlsSetupFailureRtcp : kDtlsSetupFailureRtp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764}
1765
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001766void WebRtcSession::OnDataChannelMessageReceived(
1767 cricket::DataChannel* channel,
1768 const cricket::ReceiveDataParams& params,
jbaucheec21bd2016-03-20 06:15:43 -07001769 const rtc::CopyOnWriteBuffer& payload) {
deadbeefab9b2d12015-10-14 11:33:11 -07001770 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
1771 if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) {
1772 // Received OPEN message; parse and signal that a new data channel should
1773 // be created.
1774 std::string label;
1775 InternalDataChannelInit config;
1776 config.id = params.ssrc;
1777 if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
1778 LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
1779 << params.ssrc;
1780 return;
1781 }
1782 config.open_handshake_role = InternalDataChannelInit::kAcker;
1783 SignalDataChannelOpenMessage(label, config);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 }
deadbeefab9b2d12015-10-14 11:33:11 -07001785 // Otherwise ignore the message.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786}
1787
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001788// Returns false if bundle is enabled and rtcp_mux is disabled.
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001789bool WebRtcSession::ValidateBundleSettings(const SessionDescription* desc) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001790 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE);
1791 if (!bundle_enabled)
1792 return true;
1793
1794 const cricket::ContentGroup* bundle_group =
1795 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1796 ASSERT(bundle_group != NULL);
1797
1798 const cricket::ContentInfos& contents = desc->contents();
1799 for (cricket::ContentInfos::const_iterator citer = contents.begin();
1800 citer != contents.end(); ++citer) {
1801 const cricket::ContentInfo* content = (&*citer);
1802 ASSERT(content != NULL);
1803 if (bundle_group->HasContentName(content->name) &&
1804 !content->rejected && content->type == cricket::NS_JINGLE_RTP) {
1805 if (!HasRtcpMuxEnabled(content))
1806 return false;
1807 }
1808 }
1809 // RTCP-MUX is enabled in all the contents.
1810 return true;
1811}
1812
1813bool WebRtcSession::HasRtcpMuxEnabled(
1814 const cricket::ContentInfo* content) {
1815 const cricket::MediaContentDescription* description =
1816 static_cast<cricket::MediaContentDescription*>(content->description);
1817 return description->rtcp_mux();
1818}
1819
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001820bool WebRtcSession::ValidateSessionDescription(
1821 const SessionDescriptionInterface* sdesc,
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001822 cricket::ContentSource source, std::string* err_desc) {
1823 std::string type;
deadbeefd59daf82015-10-14 15:02:44 -07001824 if (error() != ERROR_NONE) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001825 return BadSdp(source, type, GetSessionErrorMsg(), err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001826 }
1827
1828 if (!sdesc || !sdesc->description()) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001829 return BadSdp(source, type, kInvalidSdp, err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001830 }
1831
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001832 type = sdesc->type();
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001833 Action action = GetAction(sdesc->type());
1834 if (source == cricket::CS_LOCAL) {
1835 if (!ExpectSetLocalDescription(action))
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001836 return BadLocalSdp(type, BadStateErrMsg(state()), err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001837 } else {
1838 if (!ExpectSetRemoteDescription(action))
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001839 return BadRemoteSdp(type, BadStateErrMsg(state()), err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001840 }
1841
1842 // Verify crypto settings.
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +00001843 std::string crypto_error;
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +00001844 if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
1845 dtls_enabled_) &&
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +00001846 !VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001847 return BadSdp(source, type, crypto_error, err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001848 }
1849
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001850 // Verify ice-ufrag and ice-pwd.
1851 if (!VerifyIceUfragPwdPresent(sdesc->description())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001852 return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001853 }
1854
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001855 if (!ValidateBundleSettings(sdesc->description())) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001856 return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001857 }
1858
skvlad6c87a672016-05-17 17:49:52 -07001859 // TODO(skvlad): When the local rtcp-mux policy is Require, reject any
1860 // m-lines that do not rtcp-mux enabled.
1861
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001862 // Verify m-lines in Answer when compared against Offer.
1863 if (action == kAnswer) {
1864 const cricket::SessionDescription* offer_desc =
deadbeeffe4a8a42016-12-20 17:56:17 -08001865 (source == cricket::CS_LOCAL) ? remote_description()->description()
1866 : local_description()->description();
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001867 if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) {
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001868 return BadAnswerSdp(source, kMlineMismatch, err_desc);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001869 }
1870 }
1871
1872 return true;
1873}
1874
1875bool WebRtcSession::ExpectSetLocalDescription(Action action) {
1876 return ((action == kOffer && state() == STATE_INIT) ||
1877 // update local offer
deadbeefd59daf82015-10-14 15:02:44 -07001878 (action == kOffer && state() == STATE_SENTOFFER) ||
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001879 // update the current ongoing session.
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001880 (action == kOffer && state() == STATE_INPROGRESS) ||
1881 // accept remote offer
deadbeefd59daf82015-10-14 15:02:44 -07001882 (action == kAnswer && state() == STATE_RECEIVEDOFFER) ||
1883 (action == kAnswer && state() == STATE_SENTPRANSWER) ||
1884 (action == kPrAnswer && state() == STATE_RECEIVEDOFFER) ||
1885 (action == kPrAnswer && state() == STATE_SENTPRANSWER));
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001886}
1887
1888bool WebRtcSession::ExpectSetRemoteDescription(Action action) {
1889 return ((action == kOffer && state() == STATE_INIT) ||
1890 // update remote offer
deadbeefd59daf82015-10-14 15:02:44 -07001891 (action == kOffer && state() == STATE_RECEIVEDOFFER) ||
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001892 // update the current ongoing session
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001893 (action == kOffer && state() == STATE_INPROGRESS) ||
1894 // accept local offer
deadbeefd59daf82015-10-14 15:02:44 -07001895 (action == kAnswer && state() == STATE_SENTOFFER) ||
1896 (action == kAnswer && state() == STATE_RECEIVEDPRANSWER) ||
1897 (action == kPrAnswer && state() == STATE_SENTOFFER) ||
1898 (action == kPrAnswer && state() == STATE_RECEIVEDPRANSWER));
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +00001899}
1900
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00001901std::string WebRtcSession::GetSessionErrorMsg() {
1902 std::ostringstream desc;
1903 desc << kSessionError << GetErrorCodeString(error()) << ". ";
1904 desc << kSessionErrorDesc << error_desc() << ".";
1905 return desc.str();
1906}
1907
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001908// We need to check the local/remote description for the Transport instead of
1909// the session, because a new Transport added during renegotiation may have
1910// them unset while the session has them set from the previous negotiation.
1911// Not doing so may trigger the auto generation of transport description and
1912// mess up DTLS identity information, ICE credential, etc.
1913bool WebRtcSession::ReadyToUseRemoteCandidate(
1914 const IceCandidateInterface* candidate,
1915 const SessionDescriptionInterface* remote_desc,
1916 bool* valid) {
zhihuang9763d562016-08-05 11:14:50 -07001917 *valid = true;
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001918
1919 const SessionDescriptionInterface* current_remote_desc =
deadbeeffe4a8a42016-12-20 17:56:17 -08001920 remote_desc ? remote_desc : remote_description();
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001921
deadbeefd59daf82015-10-14 15:02:44 -07001922 if (!current_remote_desc) {
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001923 return false;
deadbeefd59daf82015-10-14 15:02:44 -07001924 }
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001925
1926 size_t mediacontent_index =
1927 static_cast<size_t>(candidate->sdp_mline_index());
1928 size_t remote_content_size =
1929 current_remote_desc->description()->contents().size();
1930 if (mediacontent_index >= remote_content_size) {
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001931 LOG(LS_ERROR) << "ReadyToUseRemoteCandidate: Invalid candidate media index "
1932 << mediacontent_index;
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001933
1934 *valid = false;
1935 return false;
1936 }
1937
1938 cricket::ContentInfo content =
1939 current_remote_desc->description()->contents()[mediacontent_index];
zhihuang9763d562016-08-05 11:14:50 -07001940
1941 const std::string transport_name = GetTransportName(content.name);
1942 if (transport_name.empty()) {
deadbeefcbecd352015-09-23 11:50:27 -07001943 return false;
1944 }
zhihuang9763d562016-08-05 11:14:50 -07001945 return transport_controller_->ReadyForRemoteCandidates(transport_name);
jiayl@webrtc.orge10d28c2014-07-17 17:07:49 +00001946}
1947
deadbeef7af91dd2016-12-13 11:29:11 -08001948bool WebRtcSession::SrtpRequired() const {
1949 return dtls_enabled_ ||
1950 webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED;
1951}
1952
deadbeefcbecd352015-09-23 11:50:27 -07001953void WebRtcSession::OnTransportControllerGatheringState(
1954 cricket::IceGatheringState state) {
1955 ASSERT(signaling_thread()->IsCurrent());
1956 if (state == cricket::kIceGatheringGathering) {
1957 if (ice_observer_) {
1958 ice_observer_->OnIceGatheringChange(
1959 PeerConnectionInterface::kIceGatheringGathering);
1960 }
1961 } else if (state == cricket::kIceGatheringComplete) {
1962 if (ice_observer_) {
1963 ice_observer_->OnIceGatheringChange(
1964 PeerConnectionInterface::kIceGatheringComplete);
deadbeefcbecd352015-09-23 11:50:27 -07001965 }
1966 }
1967}
1968
1969void WebRtcSession::ReportTransportStats() {
1970 // Use a set so we don't report the same stats twice if two channels share
1971 // a transport.
1972 std::set<std::string> transport_names;
1973 if (voice_channel()) {
1974 transport_names.insert(voice_channel()->transport_name());
1975 }
1976 if (video_channel()) {
1977 transport_names.insert(video_channel()->transport_name());
1978 }
1979 if (data_channel()) {
1980 transport_names.insert(data_channel()->transport_name());
1981 }
1982 for (const auto& name : transport_names) {
1983 cricket::TransportStats stats;
deadbeefd59daf82015-10-14 15:02:44 -07001984 if (transport_controller_->GetStats(name, &stats)) {
deadbeefcbecd352015-09-23 11:50:27 -07001985 ReportBestConnectionState(stats);
1986 ReportNegotiatedCiphers(stats);
1987 }
1988 }
1989}
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001990// Walk through the ConnectionInfos to gather best connection usage
1991// for IPv4 and IPv6.
jbauchac8869e2015-07-03 01:36:14 -07001992void WebRtcSession::ReportBestConnectionState(
1993 const cricket::TransportStats& stats) {
henrikg91d6ede2015-09-17 00:24:34 -07001994 RTC_DCHECK(metrics_observer_ != NULL);
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001995 for (cricket::TransportChannelStatsList::const_iterator it =
1996 stats.channel_stats.begin();
1997 it != stats.channel_stats.end(); ++it) {
1998 for (cricket::ConnectionInfos::const_iterator it_info =
1999 it->connection_infos.begin();
2000 it_info != it->connection_infos.end(); ++it_info) {
2001 if (!it_info->best_connection) {
2002 continue;
2003 }
Guo-wei Shieh3d564c12015-08-19 16:51:15 -07002004
2005 PeerConnectionEnumCounterType type = kPeerConnectionEnumCounterMax;
2006 const cricket::Candidate& local = it_info->local_candidate;
2007 const cricket::Candidate& remote = it_info->remote_candidate;
2008
2009 // Increment the counter for IceCandidatePairType.
2010 if (local.protocol() == cricket::TCP_PROTOCOL_NAME ||
2011 (local.type() == RELAY_PORT_TYPE &&
2012 local.relay_protocol() == cricket::TCP_PROTOCOL_NAME)) {
2013 type = kEnumCounterIceCandidatePairTypeTcp;
2014 } else if (local.protocol() == cricket::UDP_PROTOCOL_NAME) {
2015 type = kEnumCounterIceCandidatePairTypeUdp;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00002016 } else {
henrikg91d6ede2015-09-17 00:24:34 -07002017 RTC_CHECK(0);
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00002018 }
Guo-wei Shieh3d564c12015-08-19 16:51:15 -07002019 metrics_observer_->IncrementEnumCounter(
2020 type, GetIceCandidatePairCounter(local, remote),
2021 kIceCandidatePairMax);
2022
2023 // Increment the counter for IP type.
2024 if (local.address().family() == AF_INET) {
Guo-wei Shieh3d564c12015-08-19 16:51:15 -07002025 metrics_observer_->IncrementEnumCounter(
2026 kEnumCounterAddressFamily, kBestConnections_IPv4,
2027 kPeerConnectionAddressFamilyCounter_Max);
2028
2029 } else if (local.address().family() == AF_INET6) {
Guo-wei Shieh3d564c12015-08-19 16:51:15 -07002030 metrics_observer_->IncrementEnumCounter(
2031 kEnumCounterAddressFamily, kBestConnections_IPv6,
2032 kPeerConnectionAddressFamilyCounter_Max);
2033 } else {
henrikg91d6ede2015-09-17 00:24:34 -07002034 RTC_CHECK(0);
Guo-wei Shieh3d564c12015-08-19 16:51:15 -07002035 }
2036
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00002037 return;
2038 }
2039 }
2040}
2041
jbauchac8869e2015-07-03 01:36:14 -07002042void WebRtcSession::ReportNegotiatedCiphers(
2043 const cricket::TransportStats& stats) {
henrikg91d6ede2015-09-17 00:24:34 -07002044 RTC_DCHECK(metrics_observer_ != NULL);
jbauchac8869e2015-07-03 01:36:14 -07002045 if (!dtls_enabled_ || stats.channel_stats.empty()) {
2046 return;
2047 }
2048
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -08002049 int srtp_crypto_suite = stats.channel_stats[0].srtp_crypto_suite;
2050 int ssl_cipher_suite = stats.channel_stats[0].ssl_cipher_suite;
2051 if (srtp_crypto_suite == rtc::SRTP_INVALID_CRYPTO_SUITE &&
2052 ssl_cipher_suite == rtc::TLS_NULL_WITH_NULL_NULL) {
jbauchac8869e2015-07-03 01:36:14 -07002053 return;
2054 }
2055
Guo-wei Shieh456696a2015-09-30 21:48:54 -07002056 PeerConnectionEnumCounterType srtp_counter_type;
2057 PeerConnectionEnumCounterType ssl_counter_type;
deadbeefcbecd352015-09-23 11:50:27 -07002058 if (stats.transport_name == cricket::CN_AUDIO) {
Guo-wei Shieh456696a2015-09-30 21:48:54 -07002059 srtp_counter_type = kEnumCounterAudioSrtpCipher;
2060 ssl_counter_type = kEnumCounterAudioSslCipher;
deadbeefcbecd352015-09-23 11:50:27 -07002061 } else if (stats.transport_name == cricket::CN_VIDEO) {
Guo-wei Shieh456696a2015-09-30 21:48:54 -07002062 srtp_counter_type = kEnumCounterVideoSrtpCipher;
2063 ssl_counter_type = kEnumCounterVideoSslCipher;
deadbeefcbecd352015-09-23 11:50:27 -07002064 } else if (stats.transport_name == cricket::CN_DATA) {
Guo-wei Shieh456696a2015-09-30 21:48:54 -07002065 srtp_counter_type = kEnumCounterDataSrtpCipher;
2066 ssl_counter_type = kEnumCounterDataSslCipher;
jbauchac8869e2015-07-03 01:36:14 -07002067 } else {
2068 RTC_NOTREACHED();
2069 return;
2070 }
2071
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -08002072 if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE) {
2073 metrics_observer_->IncrementSparseEnumCounter(srtp_counter_type,
2074 srtp_crypto_suite);
jbauchac8869e2015-07-03 01:36:14 -07002075 }
Guo-wei Shieh521ed7b2015-11-18 19:41:53 -08002076 if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL) {
2077 metrics_observer_->IncrementSparseEnumCounter(ssl_counter_type,
2078 ssl_cipher_suite);
jbauchac8869e2015-07-03 01:36:14 -07002079 }
2080}
2081
Danil Chapovalov33b01f22016-05-11 19:55:27 +02002082void WebRtcSession::OnSentPacket_w(const rtc::SentPacket& sent_packet) {
stefanc1aeaf02015-10-15 07:26:07 -07002083 RTC_DCHECK(worker_thread()->IsCurrent());
2084 media_controller_->call_w()->OnSentPacket(sent_packet);
2085}
2086
zhihuang9763d562016-08-05 11:14:50 -07002087const std::string WebRtcSession::GetTransportName(
2088 const std::string& content_name) {
2089 cricket::BaseChannel* channel = GetChannel(content_name);
2090 if (!channel) {
2091#ifdef HAVE_QUIC
2092 if (data_channel_type_ == cricket::DCT_QUIC && quic_data_transport_ &&
2093 content_name == quic_data_transport_->transport_name()) {
2094 return quic_data_transport_->transport_name();
2095 }
2096#endif
2097 // Return an empty string if failed to retrieve the transport name.
2098 return "";
2099 }
2100 return channel->transport_name();
2101}
zhihuangd82eee02016-08-26 11:25:05 -07002102
2103void WebRtcSession::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
2104 if (metrics_observer_) {
2105 metrics_observer_->IncrementEnumCounter(
2106 webrtc::kEnumCounterDtlsHandshakeError, static_cast<int>(error),
2107 static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
2108 }
2109}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110} // namespace webrtc