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

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

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

Powered by Google App Engine
This is Rietveld 408576698