Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: webrtc/api/webrtcsession.cc

Issue 2514883002: Create //webrtc/api:libjingle_peerconnection_api + refactorings. (Closed)
Patch Set: Rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * 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.
9 */
10
11 #include "webrtc/api/webrtcsession.h"
12
13 #include <limits.h>
14
15 #include <algorithm>
16 #include <set>
17 #include <utility>
18 #include <vector>
19
20 #include "webrtc/api/call/audio_sink.h"
21 #include "webrtc/api/jsepicecandidate.h"
22 #include "webrtc/api/jsepsessiondescription.h"
23 #include "webrtc/api/peerconnectioninterface.h"
24 #include "webrtc/api/sctputils.h"
25 #include "webrtc/api/webrtcsessiondescriptionfactory.h"
26 #include "webrtc/base/basictypes.h"
27 #include "webrtc/base/bind.h"
28 #include "webrtc/base/checks.h"
29 #include "webrtc/base/helpers.h"
30 #include "webrtc/base/logging.h"
31 #include "webrtc/base/stringencode.h"
32 #include "webrtc/base/stringutils.h"
33 #include "webrtc/call/call.h"
34 #include "webrtc/media/base/mediaconstants.h"
35 #include "webrtc/media/base/videocapturer.h"
36 #include "webrtc/p2p/base/portallocator.h"
37 #include "webrtc/p2p/base/transportchannel.h"
38 #include "webrtc/pc/channel.h"
39 #include "webrtc/pc/channelmanager.h"
40 #include "webrtc/pc/mediasession.h"
41
42 #ifdef HAVE_QUIC
43 #include "webrtc/p2p/quic/quictransportchannel.h"
44 #endif // HAVE_QUIC
45
46 using cricket::ContentInfo;
47 using cricket::ContentInfos;
48 using cricket::MediaContentDescription;
49 using cricket::SessionDescription;
50 using cricket::TransportInfo;
51
52 using cricket::LOCAL_PORT_TYPE;
53 using cricket::STUN_PORT_TYPE;
54 using cricket::RELAY_PORT_TYPE;
55 using cricket::PRFLX_PORT_TYPE;
56
57 namespace webrtc {
58
59 // Error messages
60 const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE "
61 "is enabled.";
62 const char kCreateChannelFailed[] = "Failed to create channels.";
63 const char kInvalidCandidates[] = "Description contains invalid candidates.";
64 const char kInvalidSdp[] = "Invalid session description.";
65 const char kMlineMismatch[] =
66 "Offer and answer descriptions m-lines are not matching. Rejecting answer.";
67 const char kPushDownTDFailed[] =
68 "Failed to push down transport description:";
69 const char kSdpWithoutDtlsFingerprint[] =
70 "Called with SDP without DTLS fingerprint.";
71 const char kSdpWithoutSdesCrypto[] =
72 "Called with SDP without SDES crypto.";
73 const char kSdpWithoutIceUfragPwd[] =
74 "Called with SDP without ice-ufrag and ice-pwd.";
75 const char kSessionError[] = "Session error code: ";
76 const char kSessionErrorDesc[] = "Session error description: ";
77 const char kDtlsSetupFailureRtp[] =
78 "Couldn't set up DTLS-SRTP on RTP channel.";
79 const char kDtlsSetupFailureRtcp[] =
80 "Couldn't set up DTLS-SRTP on RTCP channel.";
81 const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
82
83 IceCandidatePairType 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;
92 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 }
109 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
140 // 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.
143 static 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 }
152 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 }
161 }
162 return true;
163 }
164
165 // 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
168 // |srtp_required| check.
169 static bool VerifyCrypto(const SessionDescription* desc,
170 bool dtls_enabled,
171 std::string* error) {
172 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;
186 *error = kInvalidSdp;
187 return false;
188 }
189 if (dtls_enabled) {
190 if (!tinfo->description.identity_fingerprint) {
191 LOG(LS_WARNING) <<
192 "Session description must have DTLS fingerprint if DTLS enabled.";
193 *error = kSdpWithoutDtlsFingerprint;
194 return false;
195 }
196 } else {
197 if (media->cryptos().empty()) {
198 LOG(LS_WARNING) <<
199 "Session description must have SDES when DTLS disabled.";
200 *error = kSdpWithoutSdesCrypto;
201 return false;
202 }
203 }
204 }
205
206 return true;
207 }
208
209 // Checks that each non-rejected content has ice-ufrag and ice-pwd set.
210 static 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
234 static bool GetAudioSsrcByTrackId(const SessionDescription* session_description,
235 const std::string& track_id,
236 uint32_t* ssrc) {
237 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);
247 const cricket::StreamParams* stream =
248 cricket::GetStreamByIds(audio_content->streams(), "", track_id);
249 if (!stream) {
250 return false;
251 }
252
253 *ssrc = stream->first_ssrc();
254 return true;
255 }
256
257 static bool GetTrackIdBySsrc(const SessionDescription* session_description,
258 uint32_t ssrc,
259 std::string* track_id) {
260 ASSERT(track_id != NULL);
261
262 const cricket::ContentInfo* audio_info =
263 cricket::GetFirstAudioContent(session_description);
264 if (audio_info) {
265 const cricket::MediaContentDescription* audio_content =
266 static_cast<const cricket::MediaContentDescription*>(
267 audio_info->description);
268
269 const auto* found =
270 cricket::GetStreamBySsrc(audio_content->streams(), ssrc);
271 if (found) {
272 *track_id = found->id;
273 return true;
274 }
275 }
276
277 const cricket::ContentInfo* video_info =
278 cricket::GetFirstVideoContent(session_description);
279 if (video_info) {
280 const cricket::MediaContentDescription* video_content =
281 static_cast<const cricket::MediaContentDescription*>(
282 video_info->description);
283
284 const auto* found =
285 cricket::GetStreamBySsrc(video_content->streams(), ssrc);
286 if (found) {
287 *track_id = found->id;
288 return true;
289 }
290 }
291 return false;
292 }
293
294 static 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;
299 desc << "Failed to set " << source;
300 if (!type.empty()) {
301 desc << " " << type;
302 }
303 desc << " sdp: " << reason;
304
305 if (err_desc) {
306 *err_desc = desc.str();
307 }
308 LOG(LS_ERROR) << desc.str();
309 return false;
310 }
311
312 static bool BadSdp(cricket::ContentSource source,
313 const std::string& type,
314 const std::string& reason,
315 std::string* err_desc) {
316 if (source == cricket::CS_LOCAL) {
317 return BadSdp("local", type, reason, err_desc);
318 } else {
319 return BadSdp("remote", type, reason, err_desc);
320 }
321 }
322
323 static 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
329 static 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
335 static 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
341 static 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
348 static bool BadAnswerSdp(cricket::ContentSource source,
349 const std::string& reason,
350 std::string* err_desc) {
351 return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc);
352 }
353
354 #define GET_STRING_OF_STATE(state) \
355 case webrtc::WebRtcSession::state: \
356 result = #state; \
357 break;
358
359 static std::string GetStateString(webrtc::WebRtcSession::State state) {
360 std::string result;
361 switch (state) {
362 GET_STRING_OF_STATE(STATE_INIT)
363 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)
367 GET_STRING_OF_STATE(STATE_INPROGRESS)
368 GET_STRING_OF_STATE(STATE_CLOSED)
369 default:
370 ASSERT(false);
371 break;
372 }
373 return result;
374 }
375
376 #define GET_STRING_OF_ERROR_CODE(err) \
377 case webrtc::WebRtcSession::err: \
378 result = #err; \
379 break;
380
381 static std::string GetErrorCodeString(webrtc::WebRtcSession::Error err) {
382 std::string result;
383 switch (err) {
384 GET_STRING_OF_ERROR_CODE(ERROR_NONE)
385 GET_STRING_OF_ERROR_CODE(ERROR_CONTENT)
386 GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT)
387 default:
388 RTC_DCHECK(false);
389 break;
390 }
391 return result;
392 }
393
394 static 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
401 static std::string MakeTdErrorString(const std::string& desc) {
402 return MakeErrorString(kPushDownTDFailed, desc);
403 }
404
405 // Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
406 bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
407 const SessionDescriptionInterface* new_desc,
408 const std::string& content_name) {
409 if (!old_desc) {
410 return false;
411 }
412 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 }
436
437 WebRtcSession::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)
444 : network_thread_(network_thread),
445 worker_thread_(worker_thread),
446 signaling_thread_(signaling_thread),
447 // 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.
450 sid_(rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX)),
451 transport_controller_(std::move(transport_controller)),
452 media_controller_(media_controller),
453 channel_manager_(media_controller_->channel_manager()),
454 ice_observer_(NULL),
455 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew),
456 ice_connection_receiving_(true),
457 older_version_remote_peer_(false),
458 dtls_enabled_(false),
459 data_channel_type_(cricket::DCT_NONE),
460 metrics_observer_(NULL) {
461 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
462 transport_controller_->SignalConnectionState.connect(
463 this, &WebRtcSession::OnTransportControllerConnectionState);
464 transport_controller_->SignalReceiving.connect(
465 this, &WebRtcSession::OnTransportControllerReceiving);
466 transport_controller_->SignalGatheringState.connect(
467 this, &WebRtcSession::OnTransportControllerGatheringState);
468 transport_controller_->SignalCandidatesGathered.connect(
469 this, &WebRtcSession::OnTransportControllerCandidatesGathered);
470 transport_controller_->SignalCandidatesRemoved.connect(
471 this, &WebRtcSession::OnTransportControllerCandidatesRemoved);
472 transport_controller_->SignalDtlsHandshakeError.connect(
473 this, &WebRtcSession::OnDtlsHandshakeError);
474 }
475
476 WebRtcSession::~WebRtcSession() {
477 ASSERT(signaling_thread()->IsCurrent());
478 // Destroy video_channel_ first since it may have a pointer to the
479 // voice_channel_.
480 if (video_channel_) {
481 SignalVideoChannelDestroyed();
482 channel_manager_->DestroyVideoChannel(video_channel_.release());
483 }
484 if (voice_channel_) {
485 SignalVoiceChannelDestroyed();
486 channel_manager_->DestroyVoiceChannel(voice_channel_.release());
487 }
488 if (data_channel_) {
489 SignalDataChannelDestroyed();
490 channel_manager_->DestroyDataChannel(data_channel_.release());
491 }
492 #ifdef HAVE_QUIC
493 if (quic_data_transport_) {
494 quic_data_transport_.reset();
495 }
496 #endif
497 SignalDestroyed();
498
499 LOG(LS_INFO) << "Session: " << id() << " is destroyed.";
500 }
501
502 bool WebRtcSession::Initialize(
503 const PeerConnectionFactoryInterface::Options& options,
504 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
505 const PeerConnectionInterface::RTCConfiguration& rtc_configuration) {
506 bundle_policy_ = rtc_configuration.bundle_policy;
507 rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy;
508 transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version);
509
510 // 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
519 SetIceConfig(ParseIceConfig(rtc_configuration));
520
521 if (options.disable_encryption) {
522 dtls_enabled_ = false;
523 } else {
524 // Enable DTLS by default if we have an identity store or a certificate.
525 dtls_enabled_ = (cert_generator || certificate);
526 // |rtc_configuration| can override the default |dtls_enabled_| value.
527 if (rtc_configuration.enable_dtls_srtp) {
528 dtls_enabled_ = *(rtc_configuration.enable_dtls_srtp);
529 }
530 }
531
532 // Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
533 // It takes precendence over the disable_sctp_data_channels
534 // PeerConnectionFactoryInterface::Options.
535 if (rtc_configuration.enable_rtp_data_channel) {
536 data_channel_type_ = cricket::DCT_RTP;
537 }
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 {
552 // DTLS has to be enabled to use SCTP.
553 if (!options.disable_sctp_data_channels && dtls_enabled_) {
554 data_channel_type_ = cricket::DCT_SCTP;
555 }
556 }
557
558 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;
562
563 audio_options_.audio_jitter_buffer_max_packets =
564 rtc::Optional<int>(rtc_configuration.audio_jitter_buffer_max_packets);
565
566 audio_options_.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(
567 rtc_configuration.audio_jitter_buffer_fast_accelerate);
568
569 if (!dtls_enabled_) {
570 // Construct with DTLS disabled.
571 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
572 signaling_thread(), channel_manager_, this, id(),
573 std::unique_ptr<rtc::RTCCertificateGeneratorInterface>()));
574 } else {
575 // Construct with DTLS enabled.
576 if (!certificate) {
577 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
578 signaling_thread(), channel_manager_, this, id(),
579 std::move(cert_generator)));
580 } else {
581 // Use the already generated certificate.
582 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
583 signaling_thread(), channel_manager_, this, id(), certificate));
584 }
585 }
586
587 webrtc_session_desc_factory_->SignalCertificateReady.connect(
588 this, &WebRtcSession::OnCertificateReady);
589
590 if (options.disable_encryption) {
591 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED);
592 }
593
594 return true;
595 }
596
597 void WebRtcSession::Close() {
598 SetState(STATE_CLOSED);
599 RemoveUnusedChannels(nullptr);
600 ASSERT(!voice_channel_);
601 ASSERT(!video_channel_);
602 ASSERT(!data_channel_);
603 media_controller_->Close();
604 }
605
606 cricket::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
620 cricket::SecurePolicy WebRtcSession::SdesPolicy() const {
621 return webrtc_session_desc_factory_->SdesPolicy();
622 }
623
624 bool WebRtcSession::GetSslRole(const std::string& transport_name,
625 rtc::SSLRole* role) {
626 if (!local_desc_ || !remote_desc_) {
627 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get "
628 << "SSL Role of the session.";
629 return false;
630 }
631
632 return transport_controller_->GetSslRole(transport_name, role);
633 }
634
635 bool WebRtcSession::GetSslRole(const cricket::BaseChannel* channel,
636 rtc::SSLRole* role) {
637 return channel && GetSslRole(channel->transport_name(), role);
638 }
639
640 void WebRtcSession::CreateOffer(
641 CreateSessionDescriptionObserver* observer,
642 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
643 const cricket::MediaSessionOptions& session_options) {
644 webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);
645 }
646
647 void WebRtcSession::CreateAnswer(
648 CreateSessionDescriptionObserver* observer,
649 const cricket::MediaSessionOptions& session_options) {
650 webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
651 }
652
653 bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
654 std::string* err_desc) {
655 ASSERT(signaling_thread()->IsCurrent());
656
657 // Takes the ownership of |desc| regardless of the result.
658 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
659
660 // Validate SDP.
661 if (!ValidateSessionDescription(desc, cricket::CS_LOCAL, err_desc)) {
662 return false;
663 }
664
665 // Update the initial_offerer flag if this session is the initial_offerer.
666 Action action = GetAction(desc->type());
667 if (state() == STATE_INIT && action == kOffer) {
668 initial_offerer_ = true;
669 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
670 }
671
672 local_desc_.reset(desc_temp.release());
673
674 // Transport and Media channels will be created only when offer is set.
675 if (action == kOffer && !CreateChannels(local_desc_->description())) {
676 // TODO(mallinath) - Handle CreateChannel failure, as new local description
677 // is applied. Restore back to old description.
678 return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc);
679 }
680
681 // Remove unused channels if MediaContentDescription is rejected.
682 RemoveUnusedChannels(local_desc_->description());
683
684 if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) {
685 return false;
686 }
687
688 if (remote_desc_) {
689 // Now that we have a local description, we can push down remote candidates.
690 UseCandidatesInSessionDescription(remote_desc_.get());
691 }
692
693 pending_ice_restarts_.clear();
694
695 if (error() != ERROR_NONE) {
696 return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc);
697 }
698 return true;
699 }
700
701 bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
702 std::string* err_desc) {
703 ASSERT(signaling_thread()->IsCurrent());
704
705 // Takes the ownership of |desc| regardless of the result.
706 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
707
708 // Validate SDP.
709 if (!ValidateSessionDescription(desc, cricket::CS_REMOTE, err_desc)) {
710 return false;
711 }
712
713 std::unique_ptr<SessionDescriptionInterface> old_remote_desc(
714 remote_desc_.release());
715 remote_desc_.reset(desc_temp.release());
716
717 // Transport and Media channels will be created only when offer is set.
718 Action action = GetAction(desc->type());
719 if (action == kOffer && !CreateChannels(desc->description())) {
720 // TODO(mallinath) - Handle CreateChannel failure, as new local description
721 // is applied. Restore back to old description.
722 return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc);
723 }
724
725 // Remove unused channels if MediaContentDescription is rejected.
726 RemoveUnusedChannels(desc->description());
727
728 // NOTE: Candidates allocation will be initiated only when SetLocalDescription
729 // is called.
730 if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) {
731 return false;
732 }
733
734 if (local_desc_ && !UseCandidatesInSessionDescription(desc)) {
735 return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc);
736 }
737
738 if (old_remote_desc) {
739 for (const cricket::ContentInfo& content :
740 old_remote_desc->description()->contents()) {
741 // Check if this new SessionDescription contains new ICE ufrag and
742 // password that indicates the remote peer requests an ICE restart.
743 // TODO(deadbeef): When we start storing both the current and pending
744 // remote description, this should reset pending_ice_restarts and compare
745 // against the current description.
746 if (CheckForRemoteIceRestart(old_remote_desc.get(), desc, content.name)) {
747 if (action == kOffer) {
748 pending_ice_restarts_.insert(content.name);
749 }
750 } else {
751 // We retain all received candidates only if ICE is not restarted.
752 // When ICE is restarted, all previous candidates belong to an old
753 // generation and should not be kept.
754 // TODO(deadbeef): This goes against the W3C spec which says the remote
755 // description should only contain candidates from the last set remote
756 // description plus any candidates added since then. We should remove
757 // this once we're sure it won't break anything.
758 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
759 old_remote_desc.get(), content.name, desc);
760 }
761 }
762 }
763
764 if (error() != ERROR_NONE) {
765 return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc);
766 }
767
768 // Set the the ICE connection state to connecting since the connection may
769 // become writable with peer reflexive candidates before any remote candidate
770 // is signaled.
771 // TODO(pthatcher): This is a short-term solution for crbug/446908. A real fix
772 // is to have a new signal the indicates a change in checking state from the
773 // transport and expose a new checking() member from transport that can be
774 // read to determine the current checking state. The existing SignalConnecting
775 // actually means "gathering candidates", so cannot be be used here.
776 if (desc->type() != SessionDescriptionInterface::kOffer &&
777 ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew) {
778 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
779 }
780 return true;
781 }
782
783 void WebRtcSession::LogState(State old_state, State new_state) {
784 LOG(LS_INFO) << "Session:" << id()
785 << " Old state:" << GetStateString(old_state)
786 << " New state:" << GetStateString(new_state);
787 }
788
789 void WebRtcSession::SetState(State state) {
790 ASSERT(signaling_thread_->IsCurrent());
791 if (state != state_) {
792 LogState(state_, state);
793 state_ = state;
794 SignalState(this, state_);
795 }
796 }
797
798 void WebRtcSession::SetError(Error error, const std::string& error_desc) {
799 ASSERT(signaling_thread_->IsCurrent());
800 if (error != error_) {
801 error_ = error;
802 error_desc_ = error_desc;
803 }
804 }
805
806 bool WebRtcSession::UpdateSessionState(
807 Action action, cricket::ContentSource source,
808 std::string* err_desc) {
809 ASSERT(signaling_thread()->IsCurrent());
810
811 // If there's already a pending error then no state transition should happen.
812 // But all call-sites should be verifying this before calling us!
813 ASSERT(error() == ERROR_NONE);
814 std::string td_err;
815 if (action == kOffer) {
816 if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) {
817 return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc);
818 }
819 SetState(source == cricket::CS_LOCAL ? STATE_SENTOFFER
820 : STATE_RECEIVEDOFFER);
821 if (!PushdownMediaDescription(cricket::CA_OFFER, source, err_desc)) {
822 SetError(ERROR_CONTENT, *err_desc);
823 }
824 if (error() != ERROR_NONE) {
825 return BadOfferSdp(source, GetSessionErrorMsg(), err_desc);
826 }
827 } else if (action == kPrAnswer) {
828 if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) {
829 return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc);
830 }
831 EnableChannels();
832 SetState(source == cricket::CS_LOCAL ? STATE_SENTPRANSWER
833 : STATE_RECEIVEDPRANSWER);
834 if (!PushdownMediaDescription(cricket::CA_PRANSWER, source, err_desc)) {
835 SetError(ERROR_CONTENT, *err_desc);
836 }
837 if (error() != ERROR_NONE) {
838 return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc);
839 }
840 } else if (action == kAnswer) {
841 const cricket::ContentGroup* local_bundle =
842 local_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
843 const cricket::ContentGroup* remote_bundle =
844 remote_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
845 if (local_bundle && remote_bundle) {
846 // The answerer decides the transport to bundle on.
847 const cricket::ContentGroup* answer_bundle =
848 (source == cricket::CS_LOCAL ? local_bundle : remote_bundle);
849 if (!EnableBundle(*answer_bundle)) {
850 LOG(LS_WARNING) << "Failed to enable BUNDLE.";
851 return BadAnswerSdp(source, kEnableBundleFailed, err_desc);
852 }
853 }
854 // Only push down the transport description after enabling BUNDLE; we don't
855 // want to push down a description on a transport about to be destroyed.
856 if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) {
857 return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc);
858 }
859 EnableChannels();
860 SetState(STATE_INPROGRESS);
861 if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) {
862 SetError(ERROR_CONTENT, *err_desc);
863 }
864 if (error() != ERROR_NONE) {
865 return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc);
866 }
867 }
868 return true;
869 }
870
871 WebRtcSession::Action WebRtcSession::GetAction(const std::string& type) {
872 if (type == SessionDescriptionInterface::kOffer) {
873 return WebRtcSession::kOffer;
874 } else if (type == SessionDescriptionInterface::kPrAnswer) {
875 return WebRtcSession::kPrAnswer;
876 } else if (type == SessionDescriptionInterface::kAnswer) {
877 return WebRtcSession::kAnswer;
878 }
879 ASSERT(false && "unknown action type");
880 return WebRtcSession::kOffer;
881 }
882
883 bool WebRtcSession::PushdownMediaDescription(
884 cricket::ContentAction action,
885 cricket::ContentSource source,
886 std::string* err) {
887 auto set_content = [this, action, source, err](cricket::BaseChannel* ch) {
888 if (!ch) {
889 return true;
890 } else if (source == cricket::CS_LOCAL) {
891 return ch->PushdownLocalDescription(local_desc_->description(), action,
892 err);
893 } else {
894 return ch->PushdownRemoteDescription(remote_desc_->description(), action,
895 err);
896 }
897 };
898
899 return (set_content(voice_channel()) &&
900 set_content(video_channel()) &&
901 set_content(data_channel()));
902 }
903
904 bool WebRtcSession::PushdownTransportDescription(cricket::ContentSource source,
905 cricket::ContentAction action,
906 std::string* error_desc) {
907 RTC_DCHECK(signaling_thread()->IsCurrent());
908
909 if (source == cricket::CS_LOCAL) {
910 return PushdownLocalTransportDescription(local_desc_->description(), action,
911 error_desc);
912 }
913 return PushdownRemoteTransportDescription(remote_desc_->description(), action,
914 error_desc);
915 }
916
917 bool WebRtcSession::PushdownLocalTransportDescription(
918 const SessionDescription* sdesc,
919 cricket::ContentAction action,
920 std::string* err) {
921 RTC_DCHECK(signaling_thread()->IsCurrent());
922
923 if (!sdesc) {
924 return false;
925 }
926
927 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
928 if (!transport_controller_->SetLocalTransportDescription(
929 tinfo.content_name, tinfo.description, action, err)) {
930 return false;
931 }
932 }
933
934 return true;
935 }
936
937 bool WebRtcSession::PushdownRemoteTransportDescription(
938 const SessionDescription* sdesc,
939 cricket::ContentAction action,
940 std::string* err) {
941 RTC_DCHECK(signaling_thread()->IsCurrent());
942
943 if (!sdesc) {
944 return false;
945 }
946
947 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
948 if (!transport_controller_->SetRemoteTransportDescription(
949 tinfo.content_name, tinfo.description, action, err)) {
950 return false;
951 }
952 }
953
954 return true;
955 }
956
957 bool WebRtcSession::GetTransportDescription(
958 const SessionDescription* description,
959 const std::string& content_name,
960 cricket::TransportDescription* tdesc) {
961 if (!description || !tdesc) {
962 return false;
963 }
964 const TransportInfo* transport_info =
965 description->GetTransportInfoByName(content_name);
966 if (!transport_info) {
967 return false;
968 }
969 *tdesc = transport_info->description;
970 return true;
971 }
972
973 bool WebRtcSession::GetTransportStats(SessionStats* stats) {
974 ASSERT(signaling_thread()->IsCurrent());
975 return (GetChannelTransportStats(voice_channel(), stats) &&
976 GetChannelTransportStats(video_channel(), stats) &&
977 GetChannelTransportStats(data_channel(), stats));
978 }
979
980 bool WebRtcSession::GetChannelTransportStats(cricket::BaseChannel* ch,
981 SessionStats* stats) {
982 ASSERT(signaling_thread()->IsCurrent());
983 if (!ch) {
984 // Not using this channel.
985 return true;
986 }
987
988 const std::string& content_name = ch->content_name();
989 const std::string& transport_name = ch->transport_name();
990 stats->proxy_to_transport[content_name] = transport_name;
991 if (stats->transport_stats.find(transport_name) !=
992 stats->transport_stats.end()) {
993 // Transport stats already done for this transport.
994 return true;
995 }
996
997 cricket::TransportStats tstats;
998 if (!transport_controller_->GetStats(transport_name, &tstats)) {
999 return false;
1000 }
1001
1002 stats->transport_stats[transport_name] = tstats;
1003 return true;
1004 }
1005
1006 bool WebRtcSession::GetLocalCertificate(
1007 const std::string& transport_name,
1008 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
1009 ASSERT(signaling_thread()->IsCurrent());
1010 return transport_controller_->GetLocalCertificate(transport_name,
1011 certificate);
1012 }
1013
1014 std::unique_ptr<rtc::SSLCertificate> WebRtcSession::GetRemoteSSLCertificate(
1015 const std::string& transport_name) {
1016 ASSERT(signaling_thread()->IsCurrent());
1017 return transport_controller_->GetRemoteSSLCertificate(transport_name);
1018 }
1019
1020 bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) {
1021 const std::string* first_content_name = bundle.FirstContentName();
1022 if (!first_content_name) {
1023 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
1024 return false;
1025 }
1026 const std::string& transport_name = *first_content_name;
1027 cricket::BaseChannel* first_channel = GetChannel(transport_name);
1028
1029 #ifdef HAVE_QUIC
1030 if (quic_data_transport_ &&
1031 bundle.HasContentName(quic_data_transport_->content_name()) &&
1032 quic_data_transport_->transport_name() != transport_name) {
1033 LOG(LS_ERROR) << "Unable to BUNDLE " << quic_data_transport_->content_name()
1034 << " on " << transport_name << "with QUIC.";
1035 }
1036 #endif
1037
1038 auto maybe_set_transport = [this, bundle, transport_name,
1039 first_channel](cricket::BaseChannel* ch) {
1040 if (!ch || !bundle.HasContentName(ch->content_name())) {
1041 return true;
1042 }
1043
1044 if (ch->transport_name() == transport_name) {
1045 LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name()
1046 << " on " << transport_name << ".";
1047 return true;
1048 }
1049
1050 if (!ch->SetTransport(transport_name)) {
1051 LOG(LS_WARNING) << "Failed to enable BUNDLE for " << ch->content_name();
1052 return false;
1053 }
1054 LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on "
1055 << transport_name << ".";
1056 return true;
1057 };
1058
1059 if (!maybe_set_transport(voice_channel()) ||
1060 !maybe_set_transport(video_channel()) ||
1061 !maybe_set_transport(data_channel())) {
1062 return false;
1063 }
1064
1065 return true;
1066 }
1067
1068 bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) {
1069 if (!remote_desc_) {
1070 LOG(LS_ERROR) << "ProcessIceMessage: ICE candidates can't be added "
1071 << "without any remote session description.";
1072 return false;
1073 }
1074
1075 if (!candidate) {
1076 LOG(LS_ERROR) << "ProcessIceMessage: Candidate is NULL.";
1077 return false;
1078 }
1079
1080 bool valid = false;
1081 bool ready = ReadyToUseRemoteCandidate(candidate, NULL, &valid);
1082 if (!valid) {
1083 return false;
1084 }
1085
1086 // Add this candidate to the remote session description.
1087 if (!remote_desc_->AddCandidate(candidate)) {
1088 LOG(LS_ERROR) << "ProcessIceMessage: Candidate cannot be used.";
1089 return false;
1090 }
1091
1092 if (ready) {
1093 return UseCandidate(candidate);
1094 } else {
1095 LOG(LS_INFO) << "ProcessIceMessage: Not ready to use candidate.";
1096 return true;
1097 }
1098 }
1099
1100 bool WebRtcSession::RemoveRemoteIceCandidates(
1101 const std::vector<cricket::Candidate>& candidates) {
1102 if (!remote_desc_) {
1103 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: ICE candidates can't be "
1104 << "removed without any remote session description.";
1105 return false;
1106 }
1107
1108 if (candidates.empty()) {
1109 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: candidates are empty.";
1110 return false;
1111 }
1112
1113 size_t number_removed = remote_desc_->RemoveCandidates(candidates);
1114 if (number_removed != candidates.size()) {
1115 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: Failed to remove candidates. "
1116 << "Requested " << candidates.size() << " but only "
1117 << number_removed << " are removed.";
1118 }
1119
1120 // Remove the candidates from the transport controller.
1121 std::string error;
1122 bool res = transport_controller_->RemoveRemoteCandidates(candidates, &error);
1123 if (!res && !error.empty()) {
1124 LOG(LS_ERROR) << "Error when removing remote candidates: " << error;
1125 }
1126 return true;
1127 }
1128
1129 cricket::IceConfig WebRtcSession::ParseIceConfig(
1130 const PeerConnectionInterface::RTCConfiguration& config) const {
1131 cricket::ContinualGatheringPolicy gathering_policy;
1132 // TODO(honghaiz): Add the third continual gathering policy in
1133 // PeerConnectionInterface and map it to GATHER_CONTINUALLY_AND_RECOVER.
1134 switch (config.continual_gathering_policy) {
1135 case PeerConnectionInterface::GATHER_ONCE:
1136 gathering_policy = cricket::GATHER_ONCE;
1137 break;
1138 case PeerConnectionInterface::GATHER_CONTINUALLY:
1139 gathering_policy = cricket::GATHER_CONTINUALLY;
1140 break;
1141 default:
1142 RTC_DCHECK(false);
1143 gathering_policy = cricket::GATHER_ONCE;
1144 }
1145 cricket::IceConfig ice_config;
1146 ice_config.receiving_timeout = config.ice_connection_receiving_timeout;
1147 ice_config.prioritize_most_likely_candidate_pairs =
1148 config.prioritize_most_likely_ice_candidate_pairs;
1149 ice_config.backup_connection_ping_interval =
1150 config.ice_backup_candidate_pair_ping_interval;
1151 ice_config.continual_gathering_policy = gathering_policy;
1152 ice_config.presume_writable_when_fully_relayed =
1153 config.presume_writable_when_fully_relayed;
1154 return ice_config;
1155 }
1156
1157 void WebRtcSession::SetIceConfig(const cricket::IceConfig& config) {
1158 transport_controller_->SetIceConfig(config);
1159 }
1160
1161 void WebRtcSession::MaybeStartGathering() {
1162 transport_controller_->MaybeStartGathering();
1163 }
1164
1165 bool WebRtcSession::GetLocalTrackIdBySsrc(uint32_t ssrc,
1166 std::string* track_id) {
1167 if (!local_desc_) {
1168 return false;
1169 }
1170 return webrtc::GetTrackIdBySsrc(local_desc_->description(), ssrc, track_id);
1171 }
1172
1173 bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32_t ssrc,
1174 std::string* track_id) {
1175 if (!remote_desc_) {
1176 return false;
1177 }
1178 return webrtc::GetTrackIdBySsrc(remote_desc_->description(), ssrc, track_id);
1179 }
1180
1181 std::string WebRtcSession::BadStateErrMsg(State state) {
1182 std::ostringstream desc;
1183 desc << "Called in wrong state: " << GetStateString(state);
1184 return desc.str();
1185 }
1186
1187 bool WebRtcSession::CanInsertDtmf(const std::string& track_id) {
1188 ASSERT(signaling_thread()->IsCurrent());
1189 if (!voice_channel_) {
1190 LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
1191 return false;
1192 }
1193 uint32_t send_ssrc = 0;
1194 // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc
1195 // exists.
1196 if (!local_desc_ ||
1197 !GetAudioSsrcByTrackId(local_desc_->description(), track_id,
1198 &send_ssrc)) {
1199 LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id;
1200 return false;
1201 }
1202 return voice_channel_->CanInsertDtmf();
1203 }
1204
1205 bool WebRtcSession::InsertDtmf(const std::string& track_id,
1206 int code, int duration) {
1207 ASSERT(signaling_thread()->IsCurrent());
1208 if (!voice_channel_) {
1209 LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
1210 return false;
1211 }
1212 uint32_t send_ssrc = 0;
1213 if (!VERIFY(local_desc_ && GetAudioSsrcByTrackId(local_desc_->description(),
1214 track_id, &send_ssrc))) {
1215 LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id;
1216 return false;
1217 }
1218 if (!voice_channel_->InsertDtmf(send_ssrc, code, duration)) {
1219 LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
1220 return false;
1221 }
1222 return true;
1223 }
1224
1225 sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() {
1226 return &SignalDestroyed;
1227 }
1228
1229 bool WebRtcSession::SendData(const cricket::SendDataParams& params,
1230 const rtc::CopyOnWriteBuffer& payload,
1231 cricket::SendDataResult* result) {
1232 if (!data_channel_) {
1233 LOG(LS_ERROR) << "SendData called when data_channel_ is NULL.";
1234 return false;
1235 }
1236 return data_channel_->SendData(params, payload, result);
1237 }
1238
1239 bool WebRtcSession::ConnectDataChannel(DataChannel* webrtc_data_channel) {
1240 if (!data_channel_) {
1241 // Don't log an error here, because DataChannels are expected to call
1242 // ConnectDataChannel in this state. It's the only way to initially tell
1243 // whether or not the underlying transport is ready.
1244 return false;
1245 }
1246 data_channel_->SignalReadyToSendData.connect(webrtc_data_channel,
1247 &DataChannel::OnChannelReady);
1248 data_channel_->SignalDataReceived.connect(webrtc_data_channel,
1249 &DataChannel::OnDataReceived);
1250 data_channel_->SignalStreamClosedRemotely.connect(
1251 webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
1252 return true;
1253 }
1254
1255 void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) {
1256 if (!data_channel_) {
1257 LOG(LS_ERROR) << "DisconnectDataChannel called when data_channel_ is NULL.";
1258 return;
1259 }
1260 data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
1261 data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
1262 data_channel_->SignalStreamClosedRemotely.disconnect(webrtc_data_channel);
1263 }
1264
1265 void WebRtcSession::AddSctpDataStream(int sid) {
1266 if (!data_channel_) {
1267 LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL.";
1268 return;
1269 }
1270 data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid));
1271 data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid));
1272 }
1273
1274 void WebRtcSession::RemoveSctpDataStream(int sid) {
1275 if (!data_channel_) {
1276 LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
1277 << "NULL.";
1278 return;
1279 }
1280 data_channel_->RemoveRecvStream(sid);
1281 data_channel_->RemoveSendStream(sid);
1282 }
1283
1284 bool WebRtcSession::ReadyToSendData() const {
1285 return data_channel_ && data_channel_->ready_to_send_data();
1286 }
1287
1288 cricket::DataChannelType WebRtcSession::data_channel_type() const {
1289 return data_channel_type_;
1290 }
1291
1292 bool WebRtcSession::IceRestartPending(const std::string& content_name) const {
1293 return pending_ice_restarts_.find(content_name) !=
1294 pending_ice_restarts_.end();
1295 }
1296
1297 void WebRtcSession::SetNeedsIceRestartFlag() {
1298 transport_controller_->SetNeedsIceRestartFlag();
1299 }
1300
1301 bool WebRtcSession::NeedsIceRestart(const std::string& content_name) const {
1302 return transport_controller_->NeedsIceRestart(content_name);
1303 }
1304
1305 void WebRtcSession::OnCertificateReady(
1306 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
1307 transport_controller_->SetLocalCertificate(certificate);
1308 }
1309
1310 bool WebRtcSession::waiting_for_certificate_for_testing() const {
1311 return webrtc_session_desc_factory_->waiting_for_certificate_for_testing();
1312 }
1313
1314 const rtc::scoped_refptr<rtc::RTCCertificate>&
1315 WebRtcSession::certificate_for_testing() {
1316 return transport_controller_->certificate_for_testing();
1317 }
1318
1319 void WebRtcSession::SetIceConnectionState(
1320 PeerConnectionInterface::IceConnectionState state) {
1321 if (ice_connection_state_ == state) {
1322 return;
1323 }
1324
1325 LOG(LS_INFO) << "Changing IceConnectionState " << ice_connection_state_
1326 << " => " << state;
1327 RTC_DCHECK(ice_connection_state_ !=
1328 PeerConnectionInterface::kIceConnectionClosed);
1329 ice_connection_state_ = state;
1330 if (ice_observer_) {
1331 ice_observer_->OnIceConnectionChange(ice_connection_state_);
1332 }
1333 }
1334
1335 void WebRtcSession::OnTransportControllerConnectionState(
1336 cricket::IceConnectionState state) {
1337 switch (state) {
1338 case cricket::kIceConnectionConnecting:
1339 // If the current state is Connected or Completed, then there were
1340 // writable channels but now there are not, so the next state must
1341 // be Disconnected.
1342 // kIceConnectionConnecting is currently used as the default,
1343 // un-connected state by the TransportController, so its only use is
1344 // detecting disconnections.
1345 if (ice_connection_state_ ==
1346 PeerConnectionInterface::kIceConnectionConnected ||
1347 ice_connection_state_ ==
1348 PeerConnectionInterface::kIceConnectionCompleted) {
1349 SetIceConnectionState(
1350 PeerConnectionInterface::kIceConnectionDisconnected);
1351 }
1352 break;
1353 case cricket::kIceConnectionFailed:
1354 SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
1355 break;
1356 case cricket::kIceConnectionConnected:
1357 LOG(LS_INFO) << "Changing to ICE connected state because "
1358 << "all transports are writable.";
1359 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
1360 break;
1361 case cricket::kIceConnectionCompleted:
1362 LOG(LS_INFO) << "Changing to ICE completed state because "
1363 << "all transports are complete.";
1364 if (ice_connection_state_ !=
1365 PeerConnectionInterface::kIceConnectionConnected) {
1366 // If jumping directly from "checking" to "connected",
1367 // signal "connected" first.
1368 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
1369 }
1370 SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
1371 if (metrics_observer_) {
1372 ReportTransportStats();
1373 }
1374 break;
1375 default:
1376 ASSERT(false);
1377 }
1378 }
1379
1380 void WebRtcSession::OnTransportControllerReceiving(bool receiving) {
1381 SetIceConnectionReceiving(receiving);
1382 }
1383
1384 void WebRtcSession::SetIceConnectionReceiving(bool receiving) {
1385 if (ice_connection_receiving_ == receiving) {
1386 return;
1387 }
1388 ice_connection_receiving_ = receiving;
1389 if (ice_observer_) {
1390 ice_observer_->OnIceConnectionReceivingChange(receiving);
1391 }
1392 }
1393
1394 void WebRtcSession::OnTransportControllerCandidatesGathered(
1395 const std::string& transport_name,
1396 const cricket::Candidates& candidates) {
1397 ASSERT(signaling_thread()->IsCurrent());
1398 int sdp_mline_index;
1399 if (!GetLocalCandidateMediaIndex(transport_name, &sdp_mline_index)) {
1400 LOG(LS_ERROR) << "OnTransportControllerCandidatesGathered: content name "
1401 << transport_name << " not found";
1402 return;
1403 }
1404
1405 for (cricket::Candidates::const_iterator citer = candidates.begin();
1406 citer != candidates.end(); ++citer) {
1407 // Use transport_name as the candidate media id.
1408 JsepIceCandidate candidate(transport_name, sdp_mline_index, *citer);
1409 if (ice_observer_) {
1410 ice_observer_->OnIceCandidate(&candidate);
1411 }
1412 if (local_desc_) {
1413 local_desc_->AddCandidate(&candidate);
1414 }
1415 }
1416 }
1417
1418 void WebRtcSession::OnTransportControllerCandidatesRemoved(
1419 const std::vector<cricket::Candidate>& candidates) {
1420 ASSERT(signaling_thread()->IsCurrent());
1421 // Sanity check.
1422 for (const cricket::Candidate& candidate : candidates) {
1423 if (candidate.transport_name().empty()) {
1424 LOG(LS_ERROR) << "OnTransportControllerCandidatesRemoved: "
1425 << "empty content name in candidate "
1426 << candidate.ToString();
1427 return;
1428 }
1429 }
1430
1431 if (local_desc_) {
1432 local_desc_->RemoveCandidates(candidates);
1433 }
1434 if (ice_observer_) {
1435 ice_observer_->OnIceCandidatesRemoved(candidates);
1436 }
1437 }
1438
1439 // Enabling voice and video channel.
1440 void WebRtcSession::EnableChannels() {
1441 if (voice_channel_ && !voice_channel_->enabled())
1442 voice_channel_->Enable(true);
1443
1444 if (video_channel_ && !video_channel_->enabled())
1445 video_channel_->Enable(true);
1446
1447 if (data_channel_ && !data_channel_->enabled())
1448 data_channel_->Enable(true);
1449 }
1450
1451 // Returns the media index for a local ice candidate given the content name.
1452 bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name,
1453 int* sdp_mline_index) {
1454 if (!local_desc_ || !sdp_mline_index) {
1455 return false;
1456 }
1457
1458 bool content_found = false;
1459 const ContentInfos& contents = local_desc_->description()->contents();
1460 for (size_t index = 0; index < contents.size(); ++index) {
1461 if (contents[index].name == content_name) {
1462 *sdp_mline_index = static_cast<int>(index);
1463 content_found = true;
1464 break;
1465 }
1466 }
1467 return content_found;
1468 }
1469
1470 bool WebRtcSession::UseCandidatesInSessionDescription(
1471 const SessionDescriptionInterface* remote_desc) {
1472 if (!remote_desc) {
1473 return true;
1474 }
1475 bool ret = true;
1476
1477 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) {
1478 const IceCandidateCollection* candidates = remote_desc->candidates(m);
1479 for (size_t n = 0; n < candidates->count(); ++n) {
1480 const IceCandidateInterface* candidate = candidates->at(n);
1481 bool valid = false;
1482 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) {
1483 if (valid) {
1484 LOG(LS_INFO) << "UseCandidatesInSessionDescription: Not ready to use "
1485 << "candidate.";
1486 }
1487 continue;
1488 }
1489 ret = UseCandidate(candidate);
1490 if (!ret) {
1491 break;
1492 }
1493 }
1494 }
1495 return ret;
1496 }
1497
1498 bool WebRtcSession::UseCandidate(const IceCandidateInterface* candidate) {
1499 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index());
1500 size_t remote_content_size = remote_desc_->description()->contents().size();
1501 if (mediacontent_index >= remote_content_size) {
1502 LOG(LS_ERROR) << "UseCandidate: Invalid candidate media index.";
1503 return false;
1504 }
1505
1506 cricket::ContentInfo content =
1507 remote_desc_->description()->contents()[mediacontent_index];
1508 std::vector<cricket::Candidate> candidates;
1509 candidates.push_back(candidate->candidate());
1510 // Invoking BaseSession method to handle remote candidates.
1511 std::string error;
1512 if (transport_controller_->AddRemoteCandidates(content.name, candidates,
1513 &error)) {
1514 // Candidates successfully submitted for checking.
1515 if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew ||
1516 ice_connection_state_ ==
1517 PeerConnectionInterface::kIceConnectionDisconnected) {
1518 // If state is New, then the session has just gotten its first remote ICE
1519 // candidates, so go to Checking.
1520 // If state is Disconnected, the session is re-using old candidates or
1521 // receiving additional ones, so go to Checking.
1522 // If state is Connected, stay Connected.
1523 // TODO(bemasc): If state is Connected, and the new candidates are for a
1524 // newly added transport, then the state actually _should_ move to
1525 // checking. Add a way to distinguish that case.
1526 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
1527 }
1528 // TODO(bemasc): If state is Completed, go back to Connected.
1529 } else {
1530 if (!error.empty()) {
1531 LOG(LS_WARNING) << error;
1532 }
1533 }
1534 return true;
1535 }
1536
1537 void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) {
1538 // Destroy video_channel_ first since it may have a pointer to the
1539 // voice_channel_.
1540 const cricket::ContentInfo* video_info =
1541 cricket::GetFirstVideoContent(desc);
1542 if ((!video_info || video_info->rejected) && video_channel_) {
1543 SignalVideoChannelDestroyed();
1544 channel_manager_->DestroyVideoChannel(video_channel_.release());
1545 }
1546
1547 const cricket::ContentInfo* voice_info =
1548 cricket::GetFirstAudioContent(desc);
1549 if ((!voice_info || voice_info->rejected) && voice_channel_) {
1550 SignalVoiceChannelDestroyed();
1551 channel_manager_->DestroyVoiceChannel(voice_channel_.release());
1552 }
1553
1554 const cricket::ContentInfo* data_info =
1555 cricket::GetFirstDataContent(desc);
1556 if (!data_info || data_info->rejected) {
1557 if (data_channel_) {
1558 SignalDataChannelDestroyed();
1559 channel_manager_->DestroyDataChannel(data_channel_.release());
1560 }
1561 #ifdef HAVE_QUIC
1562 // Clean up the existing QuicDataTransport and its QuicTransportChannels.
1563 if (quic_data_transport_) {
1564 quic_data_transport_.reset();
1565 }
1566 #endif
1567 }
1568 }
1569
1570 // Returns the name of the transport channel when BUNDLE is enabled, or nullptr
1571 // if the channel is not part of any bundle.
1572 const std::string* WebRtcSession::GetBundleTransportName(
1573 const cricket::ContentInfo* content,
1574 const cricket::ContentGroup* bundle) {
1575 if (!bundle) {
1576 return nullptr;
1577 }
1578 const std::string* first_content_name = bundle->FirstContentName();
1579 if (!first_content_name) {
1580 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
1581 return nullptr;
1582 }
1583 if (!bundle->HasContentName(content->name)) {
1584 LOG(LS_WARNING) << content->name << " is not part of any bundle group";
1585 return nullptr;
1586 }
1587 LOG(LS_INFO) << "Bundling " << content->name << " on " << *first_content_name;
1588 return first_content_name;
1589 }
1590
1591 bool WebRtcSession::CreateChannels(const SessionDescription* desc) {
1592 const cricket::ContentGroup* bundle_group = nullptr;
1593 if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle) {
1594 bundle_group = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1595 if (!bundle_group) {
1596 LOG(LS_WARNING) << "max-bundle specified without BUNDLE specified";
1597 return false;
1598 }
1599 }
1600 // Creating the media channels and transport proxies.
1601 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc);
1602 if (voice && !voice->rejected && !voice_channel_) {
1603 if (!CreateVoiceChannel(voice,
1604 GetBundleTransportName(voice, bundle_group))) {
1605 LOG(LS_ERROR) << "Failed to create voice channel.";
1606 return false;
1607 }
1608 }
1609
1610 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc);
1611 if (video && !video->rejected && !video_channel_) {
1612 if (!CreateVideoChannel(video,
1613 GetBundleTransportName(video, bundle_group))) {
1614 LOG(LS_ERROR) << "Failed to create video channel.";
1615 return false;
1616 }
1617 }
1618
1619 const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc);
1620 if (data_channel_type_ != cricket::DCT_NONE &&
1621 data && !data->rejected && !data_channel_) {
1622 if (!CreateDataChannel(data, GetBundleTransportName(data, bundle_group))) {
1623 LOG(LS_ERROR) << "Failed to create data channel.";
1624 return false;
1625 }
1626 }
1627
1628 return true;
1629 }
1630
1631 bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content,
1632 const std::string* bundle_transport) {
1633 bool require_rtcp_mux =
1634 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1635 bool create_rtcp_transport_channel = !require_rtcp_mux;
1636 voice_channel_.reset(channel_manager_->CreateVoiceChannel(
1637 media_controller_, transport_controller_.get(), content->name,
1638 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1639 audio_options_));
1640 if (!voice_channel_) {
1641 return false;
1642 }
1643 if (require_rtcp_mux) {
1644 voice_channel_->ActivateRtcpMux();
1645 }
1646
1647 voice_channel_->SignalDtlsSetupFailure.connect(
1648 this, &WebRtcSession::OnDtlsSetupFailure);
1649
1650 SignalVoiceChannelCreated();
1651 voice_channel_->SignalSentPacket.connect(this,
1652 &WebRtcSession::OnSentPacket_w);
1653 return true;
1654 }
1655
1656 bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content,
1657 const std::string* bundle_transport) {
1658 bool require_rtcp_mux =
1659 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1660 bool create_rtcp_transport_channel = !require_rtcp_mux;
1661 video_channel_.reset(channel_manager_->CreateVideoChannel(
1662 media_controller_, transport_controller_.get(), content->name,
1663 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1664 video_options_));
1665 if (!video_channel_) {
1666 return false;
1667 }
1668 if (require_rtcp_mux) {
1669 video_channel_->ActivateRtcpMux();
1670 }
1671 video_channel_->SignalDtlsSetupFailure.connect(
1672 this, &WebRtcSession::OnDtlsSetupFailure);
1673
1674 SignalVideoChannelCreated();
1675 video_channel_->SignalSentPacket.connect(this,
1676 &WebRtcSession::OnSentPacket_w);
1677 return true;
1678 }
1679
1680 bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content,
1681 const std::string* bundle_transport) {
1682 #ifdef HAVE_QUIC
1683 if (data_channel_type_ == cricket::DCT_QUIC) {
1684 RTC_DCHECK(transport_controller_->quic());
1685 const std::string transport_name =
1686 bundle_transport ? *bundle_transport : content->name;
1687 quic_data_transport_->SetTransport(transport_name);
1688 return true;
1689 }
1690 #endif // HAVE_QUIC
1691 bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
1692 bool require_rtcp_mux =
1693 rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire;
1694 bool create_rtcp_transport_channel = !sctp && !require_rtcp_mux;
1695 data_channel_.reset(channel_manager_->CreateDataChannel(
1696 media_controller_, transport_controller_.get(), content->name,
1697 bundle_transport, create_rtcp_transport_channel, SrtpRequired(),
1698 data_channel_type_));
1699 if (!data_channel_) {
1700 return false;
1701 }
1702 if (require_rtcp_mux) {
1703 data_channel_->ActivateRtcpMux();
1704 }
1705
1706 if (sctp) {
1707 data_channel_->SignalDataReceived.connect(
1708 this, &WebRtcSession::OnDataChannelMessageReceived);
1709 }
1710
1711 data_channel_->SignalDtlsSetupFailure.connect(
1712 this, &WebRtcSession::OnDtlsSetupFailure);
1713
1714 SignalDataChannelCreated();
1715 data_channel_->SignalSentPacket.connect(this, &WebRtcSession::OnSentPacket_w);
1716 return true;
1717 }
1718
1719 void WebRtcSession::OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp) {
1720 SetError(ERROR_TRANSPORT,
1721 rtcp ? kDtlsSetupFailureRtcp : kDtlsSetupFailureRtp);
1722 }
1723
1724 void WebRtcSession::OnDataChannelMessageReceived(
1725 cricket::DataChannel* channel,
1726 const cricket::ReceiveDataParams& params,
1727 const rtc::CopyOnWriteBuffer& payload) {
1728 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
1729 if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) {
1730 // Received OPEN message; parse and signal that a new data channel should
1731 // be created.
1732 std::string label;
1733 InternalDataChannelInit config;
1734 config.id = params.ssrc;
1735 if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
1736 LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
1737 << params.ssrc;
1738 return;
1739 }
1740 config.open_handshake_role = InternalDataChannelInit::kAcker;
1741 SignalDataChannelOpenMessage(label, config);
1742 }
1743 // Otherwise ignore the message.
1744 }
1745
1746 // Returns false if bundle is enabled and rtcp_mux is disabled.
1747 bool WebRtcSession::ValidateBundleSettings(const SessionDescription* desc) {
1748 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE);
1749 if (!bundle_enabled)
1750 return true;
1751
1752 const cricket::ContentGroup* bundle_group =
1753 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1754 ASSERT(bundle_group != NULL);
1755
1756 const cricket::ContentInfos& contents = desc->contents();
1757 for (cricket::ContentInfos::const_iterator citer = contents.begin();
1758 citer != contents.end(); ++citer) {
1759 const cricket::ContentInfo* content = (&*citer);
1760 ASSERT(content != NULL);
1761 if (bundle_group->HasContentName(content->name) &&
1762 !content->rejected && content->type == cricket::NS_JINGLE_RTP) {
1763 if (!HasRtcpMuxEnabled(content))
1764 return false;
1765 }
1766 }
1767 // RTCP-MUX is enabled in all the contents.
1768 return true;
1769 }
1770
1771 bool WebRtcSession::HasRtcpMuxEnabled(
1772 const cricket::ContentInfo* content) {
1773 const cricket::MediaContentDescription* description =
1774 static_cast<cricket::MediaContentDescription*>(content->description);
1775 return description->rtcp_mux();
1776 }
1777
1778 bool WebRtcSession::ValidateSessionDescription(
1779 const SessionDescriptionInterface* sdesc,
1780 cricket::ContentSource source, std::string* err_desc) {
1781 std::string type;
1782 if (error() != ERROR_NONE) {
1783 return BadSdp(source, type, GetSessionErrorMsg(), err_desc);
1784 }
1785
1786 if (!sdesc || !sdesc->description()) {
1787 return BadSdp(source, type, kInvalidSdp, err_desc);
1788 }
1789
1790 type = sdesc->type();
1791 Action action = GetAction(sdesc->type());
1792 if (source == cricket::CS_LOCAL) {
1793 if (!ExpectSetLocalDescription(action))
1794 return BadLocalSdp(type, BadStateErrMsg(state()), err_desc);
1795 } else {
1796 if (!ExpectSetRemoteDescription(action))
1797 return BadRemoteSdp(type, BadStateErrMsg(state()), err_desc);
1798 }
1799
1800 // Verify crypto settings.
1801 std::string crypto_error;
1802 if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
1803 dtls_enabled_) &&
1804 !VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) {
1805 return BadSdp(source, type, crypto_error, err_desc);
1806 }
1807
1808 // Verify ice-ufrag and ice-pwd.
1809 if (!VerifyIceUfragPwdPresent(sdesc->description())) {
1810 return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc);
1811 }
1812
1813 if (!ValidateBundleSettings(sdesc->description())) {
1814 return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc);
1815 }
1816
1817 // TODO(skvlad): When the local rtcp-mux policy is Require, reject any
1818 // m-lines that do not rtcp-mux enabled.
1819
1820 // Verify m-lines in Answer when compared against Offer.
1821 if (action == kAnswer) {
1822 const cricket::SessionDescription* offer_desc =
1823 (source == cricket::CS_LOCAL) ? remote_desc_->description()
1824 : local_desc_->description();
1825 if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) {
1826 return BadAnswerSdp(source, kMlineMismatch, err_desc);
1827 }
1828 }
1829
1830 return true;
1831 }
1832
1833 bool WebRtcSession::ExpectSetLocalDescription(Action action) {
1834 return ((action == kOffer && state() == STATE_INIT) ||
1835 // update local offer
1836 (action == kOffer && state() == STATE_SENTOFFER) ||
1837 // update the current ongoing session.
1838 (action == kOffer && state() == STATE_INPROGRESS) ||
1839 // accept remote offer
1840 (action == kAnswer && state() == STATE_RECEIVEDOFFER) ||
1841 (action == kAnswer && state() == STATE_SENTPRANSWER) ||
1842 (action == kPrAnswer && state() == STATE_RECEIVEDOFFER) ||
1843 (action == kPrAnswer && state() == STATE_SENTPRANSWER));
1844 }
1845
1846 bool WebRtcSession::ExpectSetRemoteDescription(Action action) {
1847 return ((action == kOffer && state() == STATE_INIT) ||
1848 // update remote offer
1849 (action == kOffer && state() == STATE_RECEIVEDOFFER) ||
1850 // update the current ongoing session
1851 (action == kOffer && state() == STATE_INPROGRESS) ||
1852 // accept local offer
1853 (action == kAnswer && state() == STATE_SENTOFFER) ||
1854 (action == kAnswer && state() == STATE_RECEIVEDPRANSWER) ||
1855 (action == kPrAnswer && state() == STATE_SENTOFFER) ||
1856 (action == kPrAnswer && state() == STATE_RECEIVEDPRANSWER));
1857 }
1858
1859 std::string WebRtcSession::GetSessionErrorMsg() {
1860 std::ostringstream desc;
1861 desc << kSessionError << GetErrorCodeString(error()) << ". ";
1862 desc << kSessionErrorDesc << error_desc() << ".";
1863 return desc.str();
1864 }
1865
1866 // We need to check the local/remote description for the Transport instead of
1867 // the session, because a new Transport added during renegotiation may have
1868 // them unset while the session has them set from the previous negotiation.
1869 // Not doing so may trigger the auto generation of transport description and
1870 // mess up DTLS identity information, ICE credential, etc.
1871 bool WebRtcSession::ReadyToUseRemoteCandidate(
1872 const IceCandidateInterface* candidate,
1873 const SessionDescriptionInterface* remote_desc,
1874 bool* valid) {
1875 *valid = true;
1876
1877 const SessionDescriptionInterface* current_remote_desc =
1878 remote_desc ? remote_desc : remote_desc_.get();
1879
1880 if (!current_remote_desc) {
1881 return false;
1882 }
1883
1884 size_t mediacontent_index =
1885 static_cast<size_t>(candidate->sdp_mline_index());
1886 size_t remote_content_size =
1887 current_remote_desc->description()->contents().size();
1888 if (mediacontent_index >= remote_content_size) {
1889 LOG(LS_ERROR) << "ReadyToUseRemoteCandidate: Invalid candidate media index "
1890 << mediacontent_index;
1891
1892 *valid = false;
1893 return false;
1894 }
1895
1896 cricket::ContentInfo content =
1897 current_remote_desc->description()->contents()[mediacontent_index];
1898
1899 const std::string transport_name = GetTransportName(content.name);
1900 if (transport_name.empty()) {
1901 return false;
1902 }
1903 return transport_controller_->ReadyForRemoteCandidates(transport_name);
1904 }
1905
1906 bool WebRtcSession::SrtpRequired() const {
1907 return dtls_enabled_ ||
1908 webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED;
1909 }
1910
1911 void WebRtcSession::OnTransportControllerGatheringState(
1912 cricket::IceGatheringState state) {
1913 ASSERT(signaling_thread()->IsCurrent());
1914 if (state == cricket::kIceGatheringGathering) {
1915 if (ice_observer_) {
1916 ice_observer_->OnIceGatheringChange(
1917 PeerConnectionInterface::kIceGatheringGathering);
1918 }
1919 } else if (state == cricket::kIceGatheringComplete) {
1920 if (ice_observer_) {
1921 ice_observer_->OnIceGatheringChange(
1922 PeerConnectionInterface::kIceGatheringComplete);
1923 }
1924 }
1925 }
1926
1927 void WebRtcSession::ReportTransportStats() {
1928 // Use a set so we don't report the same stats twice if two channels share
1929 // a transport.
1930 std::set<std::string> transport_names;
1931 if (voice_channel()) {
1932 transport_names.insert(voice_channel()->transport_name());
1933 }
1934 if (video_channel()) {
1935 transport_names.insert(video_channel()->transport_name());
1936 }
1937 if (data_channel()) {
1938 transport_names.insert(data_channel()->transport_name());
1939 }
1940 for (const auto& name : transport_names) {
1941 cricket::TransportStats stats;
1942 if (transport_controller_->GetStats(name, &stats)) {
1943 ReportBestConnectionState(stats);
1944 ReportNegotiatedCiphers(stats);
1945 }
1946 }
1947 }
1948 // Walk through the ConnectionInfos to gather best connection usage
1949 // for IPv4 and IPv6.
1950 void WebRtcSession::ReportBestConnectionState(
1951 const cricket::TransportStats& stats) {
1952 RTC_DCHECK(metrics_observer_ != NULL);
1953 for (cricket::TransportChannelStatsList::const_iterator it =
1954 stats.channel_stats.begin();
1955 it != stats.channel_stats.end(); ++it) {
1956 for (cricket::ConnectionInfos::const_iterator it_info =
1957 it->connection_infos.begin();
1958 it_info != it->connection_infos.end(); ++it_info) {
1959 if (!it_info->best_connection) {
1960 continue;
1961 }
1962
1963 PeerConnectionEnumCounterType type = kPeerConnectionEnumCounterMax;
1964 const cricket::Candidate& local = it_info->local_candidate;
1965 const cricket::Candidate& remote = it_info->remote_candidate;
1966
1967 // Increment the counter for IceCandidatePairType.
1968 if (local.protocol() == cricket::TCP_PROTOCOL_NAME ||
1969 (local.type() == RELAY_PORT_TYPE &&
1970 local.relay_protocol() == cricket::TCP_PROTOCOL_NAME)) {
1971 type = kEnumCounterIceCandidatePairTypeTcp;
1972 } else if (local.protocol() == cricket::UDP_PROTOCOL_NAME) {
1973 type = kEnumCounterIceCandidatePairTypeUdp;
1974 } else {
1975 RTC_CHECK(0);
1976 }
1977 metrics_observer_->IncrementEnumCounter(
1978 type, GetIceCandidatePairCounter(local, remote),
1979 kIceCandidatePairMax);
1980
1981 // Increment the counter for IP type.
1982 if (local.address().family() == AF_INET) {
1983 metrics_observer_->IncrementEnumCounter(
1984 kEnumCounterAddressFamily, kBestConnections_IPv4,
1985 kPeerConnectionAddressFamilyCounter_Max);
1986
1987 } else if (local.address().family() == AF_INET6) {
1988 metrics_observer_->IncrementEnumCounter(
1989 kEnumCounterAddressFamily, kBestConnections_IPv6,
1990 kPeerConnectionAddressFamilyCounter_Max);
1991 } else {
1992 RTC_CHECK(0);
1993 }
1994
1995 return;
1996 }
1997 }
1998 }
1999
2000 void WebRtcSession::ReportNegotiatedCiphers(
2001 const cricket::TransportStats& stats) {
2002 RTC_DCHECK(metrics_observer_ != NULL);
2003 if (!dtls_enabled_ || stats.channel_stats.empty()) {
2004 return;
2005 }
2006
2007 int srtp_crypto_suite = stats.channel_stats[0].srtp_crypto_suite;
2008 int ssl_cipher_suite = stats.channel_stats[0].ssl_cipher_suite;
2009 if (srtp_crypto_suite == rtc::SRTP_INVALID_CRYPTO_SUITE &&
2010 ssl_cipher_suite == rtc::TLS_NULL_WITH_NULL_NULL) {
2011 return;
2012 }
2013
2014 PeerConnectionEnumCounterType srtp_counter_type;
2015 PeerConnectionEnumCounterType ssl_counter_type;
2016 if (stats.transport_name == cricket::CN_AUDIO) {
2017 srtp_counter_type = kEnumCounterAudioSrtpCipher;
2018 ssl_counter_type = kEnumCounterAudioSslCipher;
2019 } else if (stats.transport_name == cricket::CN_VIDEO) {
2020 srtp_counter_type = kEnumCounterVideoSrtpCipher;
2021 ssl_counter_type = kEnumCounterVideoSslCipher;
2022 } else if (stats.transport_name == cricket::CN_DATA) {
2023 srtp_counter_type = kEnumCounterDataSrtpCipher;
2024 ssl_counter_type = kEnumCounterDataSslCipher;
2025 } else {
2026 RTC_NOTREACHED();
2027 return;
2028 }
2029
2030 if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE) {
2031 metrics_observer_->IncrementSparseEnumCounter(srtp_counter_type,
2032 srtp_crypto_suite);
2033 }
2034 if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL) {
2035 metrics_observer_->IncrementSparseEnumCounter(ssl_counter_type,
2036 ssl_cipher_suite);
2037 }
2038 }
2039
2040 void WebRtcSession::OnSentPacket_w(const rtc::SentPacket& sent_packet) {
2041 RTC_DCHECK(worker_thread()->IsCurrent());
2042 media_controller_->call_w()->OnSentPacket(sent_packet);
2043 }
2044
2045 const std::string WebRtcSession::GetTransportName(
2046 const std::string& content_name) {
2047 cricket::BaseChannel* channel = GetChannel(content_name);
2048 if (!channel) {
2049 #ifdef HAVE_QUIC
2050 if (data_channel_type_ == cricket::DCT_QUIC && quic_data_transport_ &&
2051 content_name == quic_data_transport_->transport_name()) {
2052 return quic_data_transport_->transport_name();
2053 }
2054 #endif
2055 // Return an empty string if failed to retrieve the transport name.
2056 return "";
2057 }
2058 return channel->transport_name();
2059 }
2060
2061 void WebRtcSession::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
2062 if (metrics_observer_) {
2063 metrics_observer_->IncrementEnumCounter(
2064 webrtc::kEnumCounterDtlsHandshakeError, static_cast<int>(error),
2065 static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
2066 }
2067 }
2068 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698