1/* 2 * libjingle 3 * Copyright 2012 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/app/webrtc/webrtcsession.h" 29 30#include <limits.h> 31 32#include <algorithm> 33#include <set> 34#include <utility> 35#include <vector> 36 37#include "talk/app/webrtc/jsepicecandidate.h" 38#include "talk/app/webrtc/jsepsessiondescription.h" 39#include "talk/app/webrtc/mediaconstraintsinterface.h" 40#include "talk/app/webrtc/peerconnectioninterface.h" 41#include "talk/app/webrtc/sctputils.h" 42#include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" 43#include "talk/media/base/constants.h" 44#include "talk/media/base/videocapturer.h" 45#include "talk/session/media/channel.h" 46#include "talk/session/media/channelmanager.h" 47#include "talk/session/media/mediasession.h" 48#include "webrtc/audio/audio_sink.h" 49#include "webrtc/base/basictypes.h" 50#include "webrtc/base/checks.h" 51#include "webrtc/base/helpers.h" 52#include "webrtc/base/logging.h" 53#include "webrtc/base/stringencode.h" 54#include "webrtc/base/stringutils.h" 55#include "webrtc/call.h" 56#include "webrtc/p2p/base/portallocator.h" 57#include "webrtc/p2p/base/transportchannel.h" 58 59using cricket::ContentInfo; 60using cricket::ContentInfos; 61using cricket::MediaContentDescription; 62using cricket::SessionDescription; 63using cricket::TransportInfo; 64 65using cricket::LOCAL_PORT_TYPE; 66using cricket::STUN_PORT_TYPE; 67using cricket::RELAY_PORT_TYPE; 68using cricket::PRFLX_PORT_TYPE; 69 70namespace webrtc { 71 72// Error messages 73const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE " 74 "is enabled."; 75const char kCreateChannelFailed[] = "Failed to create channels."; 76const char kInvalidCandidates[] = "Description contains invalid candidates."; 77const char kInvalidSdp[] = "Invalid session description."; 78const char kMlineMismatch[] = 79 "Offer and answer descriptions m-lines are not matching. Rejecting answer."; 80const char kPushDownTDFailed[] = 81 "Failed to push down transport description:"; 82const char kSdpWithoutDtlsFingerprint[] = 83 "Called with SDP without DTLS fingerprint."; 84const char kSdpWithoutSdesCrypto[] = 85 "Called with SDP without SDES crypto."; 86const char kSdpWithoutIceUfragPwd[] = 87 "Called with SDP without ice-ufrag and ice-pwd."; 88const char kSessionError[] = "Session error code: "; 89const char kSessionErrorDesc[] = "Session error description: "; 90const char kDtlsSetupFailureRtp[] = 91 "Couldn't set up DTLS-SRTP on RTP channel."; 92const char kDtlsSetupFailureRtcp[] = 93 "Couldn't set up DTLS-SRTP on RTCP channel."; 94const char kEnableBundleFailed[] = "Failed to enable BUNDLE."; 95const int kMaxUnsignalledRecvStreams = 20; 96 97IceCandidatePairType GetIceCandidatePairCounter( 98 const cricket::Candidate& local, 99 const cricket::Candidate& remote) { 100 const auto& l = local.type(); 101 const auto& r = remote.type(); 102 const auto& host = LOCAL_PORT_TYPE; 103 const auto& srflx = STUN_PORT_TYPE; 104 const auto& relay = RELAY_PORT_TYPE; 105 const auto& prflx = PRFLX_PORT_TYPE; 106 if (l == host && r == host) { 107 bool local_private = IPIsPrivate(local.address().ipaddr()); 108 bool remote_private = IPIsPrivate(remote.address().ipaddr()); 109 if (local_private) { 110 if (remote_private) { 111 return kIceCandidatePairHostPrivateHostPrivate; 112 } else { 113 return kIceCandidatePairHostPrivateHostPublic; 114 } 115 } else { 116 if (remote_private) { 117 return kIceCandidatePairHostPublicHostPrivate; 118 } else { 119 return kIceCandidatePairHostPublicHostPublic; 120 } 121 } 122 } 123 if (l == host && r == srflx) 124 return kIceCandidatePairHostSrflx; 125 if (l == host && r == relay) 126 return kIceCandidatePairHostRelay; 127 if (l == host && r == prflx) 128 return kIceCandidatePairHostPrflx; 129 if (l == srflx && r == host) 130 return kIceCandidatePairSrflxHost; 131 if (l == srflx && r == srflx) 132 return kIceCandidatePairSrflxSrflx; 133 if (l == srflx && r == relay) 134 return kIceCandidatePairSrflxRelay; 135 if (l == srflx && r == prflx) 136 return kIceCandidatePairSrflxPrflx; 137 if (l == relay && r == host) 138 return kIceCandidatePairRelayHost; 139 if (l == relay && r == srflx) 140 return kIceCandidatePairRelaySrflx; 141 if (l == relay && r == relay) 142 return kIceCandidatePairRelayRelay; 143 if (l == relay && r == prflx) 144 return kIceCandidatePairRelayPrflx; 145 if (l == prflx && r == host) 146 return kIceCandidatePairPrflxHost; 147 if (l == prflx && r == srflx) 148 return kIceCandidatePairPrflxSrflx; 149 if (l == prflx && r == relay) 150 return kIceCandidatePairPrflxRelay; 151 return kIceCandidatePairMax; 152} 153 154// Compares |answer| against |offer|. Comparision is done 155// for number of m-lines in answer against offer. If matches true will be 156// returned otherwise false. 157static bool VerifyMediaDescriptions( 158 const SessionDescription* answer, const SessionDescription* offer) { 159 if (offer->contents().size() != answer->contents().size()) 160 return false; 161 162 for (size_t i = 0; i < offer->contents().size(); ++i) { 163 if ((offer->contents()[i].name) != answer->contents()[i].name) { 164 return false; 165 } 166 const MediaContentDescription* offer_mdesc = 167 static_cast<const MediaContentDescription*>( 168 offer->contents()[i].description); 169 const MediaContentDescription* answer_mdesc = 170 static_cast<const MediaContentDescription*>( 171 answer->contents()[i].description); 172 if (offer_mdesc->type() != answer_mdesc->type()) { 173 return false; 174 } 175 } 176 return true; 177} 178 179// Checks that each non-rejected content has SDES crypto keys or a DTLS 180// fingerprint. Mismatches, such as replying with a DTLS fingerprint to SDES 181// keys, will be caught in Transport negotiation, and backstopped by Channel's 182// |secure_required| check. 183static bool VerifyCrypto(const SessionDescription* desc, 184 bool dtls_enabled, 185 std::string* error) { 186 const ContentInfos& contents = desc->contents(); 187 for (size_t index = 0; index < contents.size(); ++index) { 188 const ContentInfo* cinfo = &contents[index]; 189 if (cinfo->rejected) { 190 continue; 191 } 192 193 // If the content isn't rejected, crypto must be present. 194 const MediaContentDescription* media = 195 static_cast<const MediaContentDescription*>(cinfo->description); 196 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name); 197 if (!media || !tinfo) { 198 // Something is not right. 199 LOG(LS_ERROR) << kInvalidSdp; 200 *error = kInvalidSdp; 201 return false; 202 } 203 if (dtls_enabled) { 204 if (!tinfo->description.identity_fingerprint) { 205 LOG(LS_WARNING) << 206 "Session description must have DTLS fingerprint if DTLS enabled."; 207 *error = kSdpWithoutDtlsFingerprint; 208 return false; 209 } 210 } else { 211 if (media->cryptos().empty()) { 212 LOG(LS_WARNING) << 213 "Session description must have SDES when DTLS disabled."; 214 *error = kSdpWithoutSdesCrypto; 215 return false; 216 } 217 } 218 } 219 220 return true; 221} 222 223// Checks that each non-rejected content has ice-ufrag and ice-pwd set. 224static bool VerifyIceUfragPwdPresent(const SessionDescription* desc) { 225 const ContentInfos& contents = desc->contents(); 226 for (size_t index = 0; index < contents.size(); ++index) { 227 const ContentInfo* cinfo = &contents[index]; 228 if (cinfo->rejected) { 229 continue; 230 } 231 232 // If the content isn't rejected, ice-ufrag and ice-pwd must be present. 233 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name); 234 if (!tinfo) { 235 // Something is not right. 236 LOG(LS_ERROR) << kInvalidSdp; 237 return false; 238 } 239 if (tinfo->description.ice_ufrag.empty() || 240 tinfo->description.ice_pwd.empty()) { 241 LOG(LS_ERROR) << "Session description must have ice ufrag and pwd."; 242 return false; 243 } 244 } 245 return true; 246} 247 248// Forces |sdesc->crypto_required| to the appropriate state based on the 249// current security policy, to ensure a failure occurs if there is an error 250// in crypto negotiation. 251// Called when processing the local session description. 252static void UpdateSessionDescriptionSecurePolicy(cricket::CryptoType type, 253 SessionDescription* sdesc) { 254 if (!sdesc) { 255 return; 256 } 257 258 // Updating the |crypto_required_| in MediaContentDescription to the 259 // appropriate state based on the current security policy. 260 for (cricket::ContentInfos::iterator iter = sdesc->contents().begin(); 261 iter != sdesc->contents().end(); ++iter) { 262 if (cricket::IsMediaContent(&*iter)) { 263 MediaContentDescription* mdesc = 264 static_cast<MediaContentDescription*> (iter->description); 265 if (mdesc) { 266 mdesc->set_crypto_required(type); 267 } 268 } 269 } 270} 271 272static bool GetAudioSsrcByTrackId(const SessionDescription* session_description, 273 const std::string& track_id, 274 uint32_t* ssrc) { 275 const cricket::ContentInfo* audio_info = 276 cricket::GetFirstAudioContent(session_description); 277 if (!audio_info) { 278 LOG(LS_ERROR) << "Audio not used in this call"; 279 return false; 280 } 281 282 const cricket::MediaContentDescription* audio_content = 283 static_cast<const cricket::MediaContentDescription*>( 284 audio_info->description); 285 const cricket::StreamParams* stream = 286 cricket::GetStreamByIds(audio_content->streams(), "", track_id); 287 if (!stream) { 288 return false; 289 } 290 291 *ssrc = stream->first_ssrc(); 292 return true; 293} 294 295static bool GetTrackIdBySsrc(const SessionDescription* session_description, 296 uint32_t ssrc, 297 std::string* track_id) { 298 ASSERT(track_id != NULL); 299 300 const cricket::ContentInfo* audio_info = 301 cricket::GetFirstAudioContent(session_description); 302 if (audio_info) { 303 const cricket::MediaContentDescription* audio_content = 304 static_cast<const cricket::MediaContentDescription*>( 305 audio_info->description); 306 307 const auto* found = 308 cricket::GetStreamBySsrc(audio_content->streams(), ssrc); 309 if (found) { 310 *track_id = found->id; 311 return true; 312 } 313 } 314 315 const cricket::ContentInfo* video_info = 316 cricket::GetFirstVideoContent(session_description); 317 if (video_info) { 318 const cricket::MediaContentDescription* video_content = 319 static_cast<const cricket::MediaContentDescription*>( 320 video_info->description); 321 322 const auto* found = 323 cricket::GetStreamBySsrc(video_content->streams(), ssrc); 324 if (found) { 325 *track_id = found->id; 326 return true; 327 } 328 } 329 return false; 330} 331 332static bool BadSdp(const std::string& source, 333 const std::string& type, 334 const std::string& reason, 335 std::string* err_desc) { 336 std::ostringstream desc; 337 desc << "Failed to set " << source; 338 if (!type.empty()) { 339 desc << " " << type; 340 } 341 desc << " sdp: " << reason; 342 343 if (err_desc) { 344 *err_desc = desc.str(); 345 } 346 LOG(LS_ERROR) << desc.str(); 347 return false; 348} 349 350static bool BadSdp(cricket::ContentSource source, 351 const std::string& type, 352 const std::string& reason, 353 std::string* err_desc) { 354 if (source == cricket::CS_LOCAL) { 355 return BadSdp("local", type, reason, err_desc); 356 } else { 357 return BadSdp("remote", type, reason, err_desc); 358 } 359} 360 361static bool BadLocalSdp(const std::string& type, 362 const std::string& reason, 363 std::string* err_desc) { 364 return BadSdp(cricket::CS_LOCAL, type, reason, err_desc); 365} 366 367static bool BadRemoteSdp(const std::string& type, 368 const std::string& reason, 369 std::string* err_desc) { 370 return BadSdp(cricket::CS_REMOTE, type, reason, err_desc); 371} 372 373static bool BadOfferSdp(cricket::ContentSource source, 374 const std::string& reason, 375 std::string* err_desc) { 376 return BadSdp(source, SessionDescriptionInterface::kOffer, reason, err_desc); 377} 378 379static bool BadPranswerSdp(cricket::ContentSource source, 380 const std::string& reason, 381 std::string* err_desc) { 382 return BadSdp(source, SessionDescriptionInterface::kPrAnswer, 383 reason, err_desc); 384} 385 386static bool BadAnswerSdp(cricket::ContentSource source, 387 const std::string& reason, 388 std::string* err_desc) { 389 return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc); 390} 391 392#define GET_STRING_OF_STATE(state) \ 393 case webrtc::WebRtcSession::state: \ 394 result = #state; \ 395 break; 396 397static std::string GetStateString(webrtc::WebRtcSession::State state) { 398 std::string result; 399 switch (state) { 400 GET_STRING_OF_STATE(STATE_INIT) 401 GET_STRING_OF_STATE(STATE_SENTOFFER) 402 GET_STRING_OF_STATE(STATE_RECEIVEDOFFER) 403 GET_STRING_OF_STATE(STATE_SENTPRANSWER) 404 GET_STRING_OF_STATE(STATE_RECEIVEDPRANSWER) 405 GET_STRING_OF_STATE(STATE_INPROGRESS) 406 GET_STRING_OF_STATE(STATE_CLOSED) 407 default: 408 ASSERT(false); 409 break; 410 } 411 return result; 412} 413 414#define GET_STRING_OF_ERROR_CODE(err) \ 415 case webrtc::WebRtcSession::err: \ 416 result = #err; \ 417 break; 418 419static std::string GetErrorCodeString(webrtc::WebRtcSession::Error err) { 420 std::string result; 421 switch (err) { 422 GET_STRING_OF_ERROR_CODE(ERROR_NONE) 423 GET_STRING_OF_ERROR_CODE(ERROR_CONTENT) 424 GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT) 425 default: 426 RTC_DCHECK(false); 427 break; 428 } 429 return result; 430} 431 432static std::string MakeErrorString(const std::string& error, 433 const std::string& desc) { 434 std::ostringstream ret; 435 ret << error << " " << desc; 436 return ret.str(); 437} 438 439static std::string MakeTdErrorString(const std::string& desc) { 440 return MakeErrorString(kPushDownTDFailed, desc); 441} 442 443// Set |option| to the highest-priority value of |key| in the optional 444// constraints if the key is found and has a valid value. 445template <typename T> 446static void SetOptionFromOptionalConstraint( 447 const MediaConstraintsInterface* constraints, 448 const std::string& key, 449 rtc::Optional<T>* option) { 450 if (!constraints) { 451 return; 452 } 453 std::string string_value; 454 T value; 455 if (constraints->GetOptional().FindFirst(key, &string_value)) { 456 if (rtc::FromString(string_value, &value)) { 457 *option = rtc::Optional<T>(value); 458 } 459 } 460} 461 462uint32_t ConvertIceTransportTypeToCandidateFilter( 463 PeerConnectionInterface::IceTransportsType type) { 464 switch (type) { 465 case PeerConnectionInterface::kNone: 466 return cricket::CF_NONE; 467 case PeerConnectionInterface::kRelay: 468 return cricket::CF_RELAY; 469 case PeerConnectionInterface::kNoHost: 470 return (cricket::CF_ALL & ~cricket::CF_HOST); 471 case PeerConnectionInterface::kAll: 472 return cricket::CF_ALL; 473 default: ASSERT(false); 474 } 475 return cricket::CF_NONE; 476} 477 478// Help class used to remember if a a remote peer has requested ice restart by 479// by sending a description with new ice ufrag and password. 480class IceRestartAnswerLatch { 481 public: 482 IceRestartAnswerLatch() : ice_restart_(false) { } 483 484 // Returns true if CheckForRemoteIceRestart has been called with a new session 485 // description where ice password and ufrag has changed since last time 486 // Reset() was called. 487 bool Get() const { 488 return ice_restart_; 489 } 490 491 void Reset() { 492 if (ice_restart_) { 493 ice_restart_ = false; 494 } 495 } 496 497 // This method has two purposes: 1. Return whether |new_desc| requests 498 // an ICE restart (i.e., new ufrag/pwd). 2. If it requests an ICE restart 499 // and it is an OFFER, remember this in |ice_restart_| so that the next 500 // Local Answer will be created with new ufrag and pwd. 501 bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc, 502 const SessionDescriptionInterface* new_desc) { 503 if (!old_desc) { 504 return false; 505 } 506 const SessionDescription* new_sd = new_desc->description(); 507 const SessionDescription* old_sd = old_desc->description(); 508 const ContentInfos& contents = new_sd->contents(); 509 for (size_t index = 0; index < contents.size(); ++index) { 510 const ContentInfo* cinfo = &contents[index]; 511 if (cinfo->rejected) { 512 continue; 513 } 514 // If the content isn't rejected, check if ufrag and password has 515 // changed. 516 const cricket::TransportDescription* new_transport_desc = 517 new_sd->GetTransportDescriptionByName(cinfo->name); 518 const cricket::TransportDescription* old_transport_desc = 519 old_sd->GetTransportDescriptionByName(cinfo->name); 520 if (!new_transport_desc || !old_transport_desc) { 521 // No transport description exist. This is not an ice restart. 522 continue; 523 } 524 if (cricket::IceCredentialsChanged(old_transport_desc->ice_ufrag, 525 old_transport_desc->ice_pwd, 526 new_transport_desc->ice_ufrag, 527 new_transport_desc->ice_pwd)) { 528 LOG(LS_INFO) << "Remote peer request ice restart."; 529 if (new_desc->type() == SessionDescriptionInterface::kOffer) { 530 ice_restart_ = true; 531 } 532 return true; 533 } 534 } 535 return false; 536 } 537 538 private: 539 bool ice_restart_; 540}; 541 542WebRtcSession::WebRtcSession(webrtc::MediaControllerInterface* media_controller, 543 rtc::Thread* signaling_thread, 544 rtc::Thread* worker_thread, 545 cricket::PortAllocator* port_allocator) 546 : signaling_thread_(signaling_thread), 547 worker_thread_(worker_thread), 548 port_allocator_(port_allocator), 549 // RFC 3264: The numeric value of the session id and version in the 550 // o line MUST be representable with a "64 bit signed integer". 551 // Due to this constraint session id |sid_| is max limited to LLONG_MAX. 552 sid_(rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX)), 553 transport_controller_(new cricket::TransportController(signaling_thread, 554 worker_thread, 555 port_allocator)), 556 media_controller_(media_controller), 557 channel_manager_(media_controller_->channel_manager()), 558 ice_observer_(NULL), 559 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew), 560 ice_connection_receiving_(true), 561 older_version_remote_peer_(false), 562 dtls_enabled_(false), 563 data_channel_type_(cricket::DCT_NONE), 564 ice_restart_latch_(new IceRestartAnswerLatch), 565 metrics_observer_(NULL) { 566 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED); 567 transport_controller_->SignalConnectionState.connect( 568 this, &WebRtcSession::OnTransportControllerConnectionState); 569 transport_controller_->SignalReceiving.connect( 570 this, &WebRtcSession::OnTransportControllerReceiving); 571 transport_controller_->SignalGatheringState.connect( 572 this, &WebRtcSession::OnTransportControllerGatheringState); 573 transport_controller_->SignalCandidatesGathered.connect( 574 this, &WebRtcSession::OnTransportControllerCandidatesGathered); 575} 576 577WebRtcSession::~WebRtcSession() { 578 ASSERT(signaling_thread()->IsCurrent()); 579 // Destroy video_channel_ first since it may have a pointer to the 580 // voice_channel_. 581 if (video_channel_) { 582 SignalVideoChannelDestroyed(); 583 channel_manager_->DestroyVideoChannel(video_channel_.release()); 584 } 585 if (voice_channel_) { 586 SignalVoiceChannelDestroyed(); 587 channel_manager_->DestroyVoiceChannel(voice_channel_.release()); 588 } 589 if (data_channel_) { 590 SignalDataChannelDestroyed(); 591 channel_manager_->DestroyDataChannel(data_channel_.release()); 592 } 593 594 LOG(LS_INFO) << "Session: " << id() << " is destroyed."; 595} 596 597bool WebRtcSession::Initialize( 598 const PeerConnectionFactoryInterface::Options& options, 599 const MediaConstraintsInterface* constraints, 600 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, 601 const PeerConnectionInterface::RTCConfiguration& rtc_configuration) { 602 bundle_policy_ = rtc_configuration.bundle_policy; 603 rtcp_mux_policy_ = rtc_configuration.rtcp_mux_policy; 604 video_options_.disable_prerenderer_smoothing = 605 rtc::Optional<bool>(rtc_configuration.disable_prerenderer_smoothing); 606 transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version); 607 608 // Obtain a certificate from RTCConfiguration if any were provided (optional). 609 rtc::scoped_refptr<rtc::RTCCertificate> certificate; 610 if (!rtc_configuration.certificates.empty()) { 611 // TODO(hbos,torbjorng): Decide on certificate-selection strategy instead of 612 // just picking the first one. The decision should be made based on the DTLS 613 // handshake. The DTLS negotiations need to know about all certificates. 614 certificate = rtc_configuration.certificates[0]; 615 } 616 617 SetIceConfig(ParseIceConfig(rtc_configuration)); 618 619 // TODO(perkj): Take |constraints| into consideration. Return false if not all 620 // mandatory constraints can be fulfilled. Note that |constraints| 621 // can be null. 622 bool value; 623 624 if (options.disable_encryption) { 625 dtls_enabled_ = false; 626 } else { 627 // Enable DTLS by default if we have an identity store or a certificate. 628 dtls_enabled_ = (dtls_identity_store || certificate); 629 // |constraints| can override the default |dtls_enabled_| value. 630 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableDtlsSrtp, 631 &value, nullptr)) { 632 dtls_enabled_ = value; 633 } 634 } 635 636 // Enable creation of RTP data channels if the kEnableRtpDataChannels is set. 637 // It takes precendence over the disable_sctp_data_channels 638 // PeerConnectionFactoryInterface::Options. 639 if (FindConstraint( 640 constraints, MediaConstraintsInterface::kEnableRtpDataChannels, 641 &value, NULL) && value) { 642 LOG(LS_INFO) << "Allowing RTP data engine."; 643 data_channel_type_ = cricket::DCT_RTP; 644 } else { 645 // DTLS has to be enabled to use SCTP. 646 if (!options.disable_sctp_data_channels && dtls_enabled_) { 647 LOG(LS_INFO) << "Allowing SCTP data engine."; 648 data_channel_type_ = cricket::DCT_SCTP; 649 } 650 } 651 652 // Find DSCP constraint. 653 if (FindConstraint( 654 constraints, 655 MediaConstraintsInterface::kEnableDscp, 656 &value, NULL)) { 657 audio_options_.dscp = rtc::Optional<bool>(value); 658 video_options_.dscp = rtc::Optional<bool>(value); 659 } 660 661 // Find Suspend Below Min Bitrate constraint. 662 if (FindConstraint( 663 constraints, 664 MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, 665 &value, 666 NULL)) { 667 video_options_.suspend_below_min_bitrate = rtc::Optional<bool>(value); 668 } 669 670 SetOptionFromOptionalConstraint(constraints, 671 MediaConstraintsInterface::kScreencastMinBitrate, 672 &video_options_.screencast_min_bitrate); 673 674 // Find constraints for cpu overuse detection. 675 SetOptionFromOptionalConstraint(constraints, 676 MediaConstraintsInterface::kCpuUnderuseThreshold, 677 &video_options_.cpu_underuse_threshold); 678 SetOptionFromOptionalConstraint(constraints, 679 MediaConstraintsInterface::kCpuOveruseThreshold, 680 &video_options_.cpu_overuse_threshold); 681 SetOptionFromOptionalConstraint(constraints, 682 MediaConstraintsInterface::kCpuOveruseDetection, 683 &video_options_.cpu_overuse_detection); 684 SetOptionFromOptionalConstraint(constraints, 685 MediaConstraintsInterface::kCpuOveruseEncodeUsage, 686 &video_options_.cpu_overuse_encode_usage); 687 SetOptionFromOptionalConstraint(constraints, 688 MediaConstraintsInterface::kCpuUnderuseEncodeRsdThreshold, 689 &video_options_.cpu_underuse_encode_rsd_threshold); 690 SetOptionFromOptionalConstraint(constraints, 691 MediaConstraintsInterface::kCpuOveruseEncodeRsdThreshold, 692 &video_options_.cpu_overuse_encode_rsd_threshold); 693 694 SetOptionFromOptionalConstraint(constraints, 695 MediaConstraintsInterface::kNumUnsignalledRecvStreams, 696 &video_options_.unsignalled_recv_stream_limit); 697 if (video_options_.unsignalled_recv_stream_limit) { 698 video_options_.unsignalled_recv_stream_limit = rtc::Optional<int>( 699 std::max(0, std::min(kMaxUnsignalledRecvStreams, 700 *video_options_.unsignalled_recv_stream_limit))); 701 } 702 703 SetOptionFromOptionalConstraint(constraints, 704 MediaConstraintsInterface::kHighStartBitrate, 705 &video_options_.video_start_bitrate); 706 707 SetOptionFromOptionalConstraint(constraints, 708 MediaConstraintsInterface::kCombinedAudioVideoBwe, 709 &audio_options_.combined_audio_video_bwe); 710 711 audio_options_.audio_jitter_buffer_max_packets = 712 rtc::Optional<int>(rtc_configuration.audio_jitter_buffer_max_packets); 713 714 audio_options_.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>( 715 rtc_configuration.audio_jitter_buffer_fast_accelerate); 716 717 if (!dtls_enabled_) { 718 // Construct with DTLS disabled. 719 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( 720 signaling_thread(), channel_manager_, this, id())); 721 } else { 722 // Construct with DTLS enabled. 723 if (!certificate) { 724 // Use the |dtls_identity_store| to generate a certificate. 725 RTC_DCHECK(dtls_identity_store); 726 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( 727 signaling_thread(), channel_manager_, std::move(dtls_identity_store), 728 this, id())); 729 } else { 730 // Use the already generated certificate. 731 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( 732 signaling_thread(), channel_manager_, certificate, this, id())); 733 } 734 } 735 736 webrtc_session_desc_factory_->SignalCertificateReady.connect( 737 this, &WebRtcSession::OnCertificateReady); 738 739 if (options.disable_encryption) { 740 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED); 741 } 742 port_allocator()->set_candidate_filter( 743 ConvertIceTransportTypeToCandidateFilter(rtc_configuration.type)); 744 745 return true; 746} 747 748void WebRtcSession::Close() { 749 SetState(STATE_CLOSED); 750 RemoveUnusedChannels(nullptr); 751 ASSERT(!voice_channel_); 752 ASSERT(!video_channel_); 753 ASSERT(!data_channel_); 754} 755 756void WebRtcSession::SetSdesPolicy(cricket::SecurePolicy secure_policy) { 757 webrtc_session_desc_factory_->SetSdesPolicy(secure_policy); 758} 759 760cricket::SecurePolicy WebRtcSession::SdesPolicy() const { 761 return webrtc_session_desc_factory_->SdesPolicy(); 762} 763 764bool WebRtcSession::GetSslRole(const std::string& transport_name, 765 rtc::SSLRole* role) { 766 if (!local_desc_ || !remote_desc_) { 767 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get " 768 << "SSL Role of the session."; 769 return false; 770 } 771 772 return transport_controller_->GetSslRole(transport_name, role); 773} 774 775bool WebRtcSession::GetSslRole(const cricket::BaseChannel* channel, 776 rtc::SSLRole* role) { 777 return channel && GetSslRole(channel->transport_name(), role); 778} 779 780void WebRtcSession::CreateOffer( 781 CreateSessionDescriptionObserver* observer, 782 const PeerConnectionInterface::RTCOfferAnswerOptions& options, 783 const cricket::MediaSessionOptions& session_options) { 784 webrtc_session_desc_factory_->CreateOffer(observer, options, session_options); 785} 786 787void WebRtcSession::CreateAnswer( 788 CreateSessionDescriptionObserver* observer, 789 const MediaConstraintsInterface* constraints, 790 const cricket::MediaSessionOptions& session_options) { 791 webrtc_session_desc_factory_->CreateAnswer(observer, constraints, 792 session_options); 793} 794 795bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc, 796 std::string* err_desc) { 797 ASSERT(signaling_thread()->IsCurrent()); 798 799 // Takes the ownership of |desc| regardless of the result. 800 rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc); 801 802 // Validate SDP. 803 if (!ValidateSessionDescription(desc, cricket::CS_LOCAL, err_desc)) { 804 return false; 805 } 806 807 // Update the initial_offerer flag if this session is the initial_offerer. 808 Action action = GetAction(desc->type()); 809 if (state() == STATE_INIT && action == kOffer) { 810 initial_offerer_ = true; 811 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING); 812 } 813 814 cricket::SecurePolicy sdes_policy = 815 webrtc_session_desc_factory_->SdesPolicy(); 816 cricket::CryptoType crypto_required = dtls_enabled_ ? 817 cricket::CT_DTLS : (sdes_policy == cricket::SEC_REQUIRED ? 818 cricket::CT_SDES : cricket::CT_NONE); 819 // Update the MediaContentDescription crypto settings as per the policy set. 820 UpdateSessionDescriptionSecurePolicy(crypto_required, desc->description()); 821 822 local_desc_.reset(desc_temp.release()); 823 824 // Transport and Media channels will be created only when offer is set. 825 if (action == kOffer && !CreateChannels(local_desc_->description())) { 826 // TODO(mallinath) - Handle CreateChannel failure, as new local description 827 // is applied. Restore back to old description. 828 return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc); 829 } 830 831 // Remove unused channels if MediaContentDescription is rejected. 832 RemoveUnusedChannels(local_desc_->description()); 833 834 if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) { 835 return false; 836 } 837 838 if (remote_desc_) { 839 // Now that we have a local description, we can push down remote candidates. 840 UseCandidatesInSessionDescription(remote_desc_.get()); 841 } 842 843 if (error() != ERROR_NONE) { 844 return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc); 845 } 846 return true; 847} 848 849bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc, 850 std::string* err_desc) { 851 ASSERT(signaling_thread()->IsCurrent()); 852 853 // Takes the ownership of |desc| regardless of the result. 854 rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc); 855 856 // Validate SDP. 857 if (!ValidateSessionDescription(desc, cricket::CS_REMOTE, err_desc)) { 858 return false; 859 } 860 861 rtc::scoped_ptr<SessionDescriptionInterface> old_remote_desc( 862 remote_desc_.release()); 863 remote_desc_.reset(desc_temp.release()); 864 865 // Transport and Media channels will be created only when offer is set. 866 Action action = GetAction(desc->type()); 867 if (action == kOffer && !CreateChannels(desc->description())) { 868 // TODO(mallinath) - Handle CreateChannel failure, as new local description 869 // is applied. Restore back to old description. 870 return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc); 871 } 872 873 // Remove unused channels if MediaContentDescription is rejected. 874 RemoveUnusedChannels(desc->description()); 875 876 // NOTE: Candidates allocation will be initiated only when SetLocalDescription 877 // is called. 878 if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) { 879 return false; 880 } 881 882 if (local_desc_ && !UseCandidatesInSessionDescription(desc)) { 883 return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc); 884 } 885 886 // Check if this new SessionDescription contains new ice ufrag and password 887 // that indicates the remote peer requests ice restart. 888 bool ice_restart = 889 ice_restart_latch_->CheckForRemoteIceRestart(old_remote_desc.get(), desc); 890 // We retain all received candidates only if ICE is not restarted. 891 // When ICE is restarted, all previous candidates belong to an old generation 892 // and should not be kept. 893 // TODO(deadbeef): This goes against the W3C spec which says the remote 894 // description should only contain candidates from the last set remote 895 // description plus any candidates added since then. We should remove this 896 // once we're sure it won't break anything. 897 if (!ice_restart) { 898 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( 899 old_remote_desc.get(), desc); 900 } 901 902 if (error() != ERROR_NONE) { 903 return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc); 904 } 905 906 // Set the the ICE connection state to connecting since the connection may 907 // become writable with peer reflexive candidates before any remote candidate 908 // is signaled. 909 // TODO(pthatcher): This is a short-term solution for crbug/446908. A real fix 910 // is to have a new signal the indicates a change in checking state from the 911 // transport and expose a new checking() member from transport that can be 912 // read to determine the current checking state. The existing SignalConnecting 913 // actually means "gathering candidates", so cannot be be used here. 914 if (desc->type() != SessionDescriptionInterface::kOffer && 915 ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew) { 916 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking); 917 } 918 return true; 919} 920 921void WebRtcSession::LogState(State old_state, State new_state) { 922 LOG(LS_INFO) << "Session:" << id() 923 << " Old state:" << GetStateString(old_state) 924 << " New state:" << GetStateString(new_state); 925} 926 927void WebRtcSession::SetState(State state) { 928 ASSERT(signaling_thread_->IsCurrent()); 929 if (state != state_) { 930 LogState(state_, state); 931 state_ = state; 932 SignalState(this, state_); 933 } 934} 935 936void WebRtcSession::SetError(Error error, const std::string& error_desc) { 937 ASSERT(signaling_thread_->IsCurrent()); 938 if (error != error_) { 939 error_ = error; 940 error_desc_ = error_desc; 941 } 942} 943 944bool WebRtcSession::UpdateSessionState( 945 Action action, cricket::ContentSource source, 946 std::string* err_desc) { 947 ASSERT(signaling_thread()->IsCurrent()); 948 949 // If there's already a pending error then no state transition should happen. 950 // But all call-sites should be verifying this before calling us! 951 ASSERT(error() == ERROR_NONE); 952 std::string td_err; 953 if (action == kOffer) { 954 if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) { 955 return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc); 956 } 957 SetState(source == cricket::CS_LOCAL ? STATE_SENTOFFER 958 : STATE_RECEIVEDOFFER); 959 if (!PushdownMediaDescription(cricket::CA_OFFER, source, err_desc)) { 960 SetError(ERROR_CONTENT, *err_desc); 961 } 962 if (error() != ERROR_NONE) { 963 return BadOfferSdp(source, GetSessionErrorMsg(), err_desc); 964 } 965 } else if (action == kPrAnswer) { 966 if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) { 967 return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc); 968 } 969 EnableChannels(); 970 SetState(source == cricket::CS_LOCAL ? STATE_SENTPRANSWER 971 : STATE_RECEIVEDPRANSWER); 972 if (!PushdownMediaDescription(cricket::CA_PRANSWER, source, err_desc)) { 973 SetError(ERROR_CONTENT, *err_desc); 974 } 975 if (error() != ERROR_NONE) { 976 return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc); 977 } 978 } else if (action == kAnswer) { 979 const cricket::ContentGroup* local_bundle = 980 local_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); 981 const cricket::ContentGroup* remote_bundle = 982 remote_desc_->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); 983 if (local_bundle && remote_bundle) { 984 // The answerer decides the transport to bundle on. 985 const cricket::ContentGroup* answer_bundle = 986 (source == cricket::CS_LOCAL ? local_bundle : remote_bundle); 987 if (!EnableBundle(*answer_bundle)) { 988 LOG(LS_WARNING) << "Failed to enable BUNDLE."; 989 return BadAnswerSdp(source, kEnableBundleFailed, err_desc); 990 } 991 } 992 // Only push down the transport description after enabling BUNDLE; we don't 993 // want to push down a description on a transport about to be destroyed. 994 if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) { 995 return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc); 996 } 997 EnableChannels(); 998 SetState(STATE_INPROGRESS); 999 if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) { 1000 SetError(ERROR_CONTENT, *err_desc); 1001 } 1002 if (error() != ERROR_NONE) { 1003 return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc); 1004 } 1005 } 1006 return true; 1007} 1008 1009WebRtcSession::Action WebRtcSession::GetAction(const std::string& type) { 1010 if (type == SessionDescriptionInterface::kOffer) { 1011 return WebRtcSession::kOffer; 1012 } else if (type == SessionDescriptionInterface::kPrAnswer) { 1013 return WebRtcSession::kPrAnswer; 1014 } else if (type == SessionDescriptionInterface::kAnswer) { 1015 return WebRtcSession::kAnswer; 1016 } 1017 ASSERT(false && "unknown action type"); 1018 return WebRtcSession::kOffer; 1019} 1020 1021bool WebRtcSession::PushdownMediaDescription( 1022 cricket::ContentAction action, 1023 cricket::ContentSource source, 1024 std::string* err) { 1025 auto set_content = [this, action, source, err](cricket::BaseChannel* ch) { 1026 if (!ch) { 1027 return true; 1028 } else if (source == cricket::CS_LOCAL) { 1029 return ch->PushdownLocalDescription(local_desc_->description(), action, 1030 err); 1031 } else { 1032 return ch->PushdownRemoteDescription(remote_desc_->description(), action, 1033 err); 1034 } 1035 }; 1036 1037 return (set_content(voice_channel()) && 1038 set_content(video_channel()) && 1039 set_content(data_channel())); 1040} 1041 1042bool WebRtcSession::PushdownTransportDescription(cricket::ContentSource source, 1043 cricket::ContentAction action, 1044 std::string* error_desc) { 1045 RTC_DCHECK(signaling_thread()->IsCurrent()); 1046 1047 if (source == cricket::CS_LOCAL) { 1048 return PushdownLocalTransportDescription(local_desc_->description(), action, 1049 error_desc); 1050 } 1051 return PushdownRemoteTransportDescription(remote_desc_->description(), action, 1052 error_desc); 1053} 1054 1055bool WebRtcSession::PushdownLocalTransportDescription( 1056 const SessionDescription* sdesc, 1057 cricket::ContentAction action, 1058 std::string* err) { 1059 RTC_DCHECK(signaling_thread()->IsCurrent()); 1060 1061 if (!sdesc) { 1062 return false; 1063 } 1064 1065 for (const TransportInfo& tinfo : sdesc->transport_infos()) { 1066 if (!transport_controller_->SetLocalTransportDescription( 1067 tinfo.content_name, tinfo.description, action, err)) { 1068 return false; 1069 } 1070 } 1071 1072 return true; 1073} 1074 1075bool WebRtcSession::PushdownRemoteTransportDescription( 1076 const SessionDescription* sdesc, 1077 cricket::ContentAction action, 1078 std::string* err) { 1079 RTC_DCHECK(signaling_thread()->IsCurrent()); 1080 1081 if (!sdesc) { 1082 return false; 1083 } 1084 1085 for (const TransportInfo& tinfo : sdesc->transport_infos()) { 1086 if (!transport_controller_->SetRemoteTransportDescription( 1087 tinfo.content_name, tinfo.description, action, err)) { 1088 return false; 1089 } 1090 } 1091 1092 return true; 1093} 1094 1095bool WebRtcSession::GetTransportDescription( 1096 const SessionDescription* description, 1097 const std::string& content_name, 1098 cricket::TransportDescription* tdesc) { 1099 if (!description || !tdesc) { 1100 return false; 1101 } 1102 const TransportInfo* transport_info = 1103 description->GetTransportInfoByName(content_name); 1104 if (!transport_info) { 1105 return false; 1106 } 1107 *tdesc = transport_info->description; 1108 return true; 1109} 1110 1111bool WebRtcSession::GetTransportStats(SessionStats* stats) { 1112 ASSERT(signaling_thread()->IsCurrent()); 1113 return (GetChannelTransportStats(voice_channel(), stats) && 1114 GetChannelTransportStats(video_channel(), stats) && 1115 GetChannelTransportStats(data_channel(), stats)); 1116} 1117 1118bool WebRtcSession::GetChannelTransportStats(cricket::BaseChannel* ch, 1119 SessionStats* stats) { 1120 ASSERT(signaling_thread()->IsCurrent()); 1121 if (!ch) { 1122 // Not using this channel. 1123 return true; 1124 } 1125 1126 const std::string& content_name = ch->content_name(); 1127 const std::string& transport_name = ch->transport_name(); 1128 stats->proxy_to_transport[content_name] = transport_name; 1129 if (stats->transport_stats.find(transport_name) != 1130 stats->transport_stats.end()) { 1131 // Transport stats already done for this transport. 1132 return true; 1133 } 1134 1135 cricket::TransportStats tstats; 1136 if (!transport_controller_->GetStats(transport_name, &tstats)) { 1137 return false; 1138 } 1139 1140 stats->transport_stats[transport_name] = tstats; 1141 return true; 1142} 1143 1144bool WebRtcSession::GetLocalCertificate( 1145 const std::string& transport_name, 1146 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) { 1147 ASSERT(signaling_thread()->IsCurrent()); 1148 return transport_controller_->GetLocalCertificate(transport_name, 1149 certificate); 1150} 1151 1152bool WebRtcSession::GetRemoteSSLCertificate(const std::string& transport_name, 1153 rtc::SSLCertificate** cert) { 1154 ASSERT(signaling_thread()->IsCurrent()); 1155 return transport_controller_->GetRemoteSSLCertificate(transport_name, cert); 1156} 1157 1158cricket::BaseChannel* WebRtcSession::GetChannel( 1159 const std::string& content_name) { 1160 if (voice_channel() && voice_channel()->content_name() == content_name) { 1161 return voice_channel(); 1162 } 1163 if (video_channel() && video_channel()->content_name() == content_name) { 1164 return video_channel(); 1165 } 1166 if (data_channel() && data_channel()->content_name() == content_name) { 1167 return data_channel(); 1168 } 1169 return nullptr; 1170} 1171 1172bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) { 1173 const std::string* first_content_name = bundle.FirstContentName(); 1174 if (!first_content_name) { 1175 LOG(LS_WARNING) << "Tried to BUNDLE with no contents."; 1176 return false; 1177 } 1178 const std::string& transport_name = *first_content_name; 1179 cricket::BaseChannel* first_channel = GetChannel(transport_name); 1180 1181 auto maybe_set_transport = [this, bundle, transport_name, 1182 first_channel](cricket::BaseChannel* ch) { 1183 if (!ch || !bundle.HasContentName(ch->content_name())) { 1184 return true; 1185 } 1186 1187 if (ch->transport_name() == transport_name) { 1188 LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name() 1189 << " on " << transport_name << "."; 1190 return true; 1191 } 1192 1193 if (!ch->SetTransport(transport_name)) { 1194 LOG(LS_WARNING) << "Failed to enable BUNDLE for " << ch->content_name(); 1195 return false; 1196 } 1197 LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on " 1198 << transport_name << "."; 1199 return true; 1200 }; 1201 1202 if (!maybe_set_transport(voice_channel()) || 1203 !maybe_set_transport(video_channel()) || 1204 !maybe_set_transport(data_channel())) { 1205 return false; 1206 } 1207 1208 return true; 1209} 1210 1211bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) { 1212 if (!remote_desc_) { 1213 LOG(LS_ERROR) << "ProcessIceMessage: ICE candidates can't be added " 1214 << "without any remote session description."; 1215 return false; 1216 } 1217 1218 if (!candidate) { 1219 LOG(LS_ERROR) << "ProcessIceMessage: Candidate is NULL."; 1220 return false; 1221 } 1222 1223 bool valid = false; 1224 bool ready = ReadyToUseRemoteCandidate(candidate, NULL, &valid); 1225 if (!valid) { 1226 return false; 1227 } 1228 1229 // Add this candidate to the remote session description. 1230 if (!remote_desc_->AddCandidate(candidate)) { 1231 LOG(LS_ERROR) << "ProcessIceMessage: Candidate cannot be used."; 1232 return false; 1233 } 1234 1235 if (ready) { 1236 return UseCandidate(candidate); 1237 } else { 1238 LOG(LS_INFO) << "ProcessIceMessage: Not ready to use candidate."; 1239 return true; 1240 } 1241} 1242 1243bool WebRtcSession::SetIceTransports( 1244 PeerConnectionInterface::IceTransportsType type) { 1245 return port_allocator()->set_candidate_filter( 1246 ConvertIceTransportTypeToCandidateFilter(type)); 1247} 1248 1249cricket::IceConfig WebRtcSession::ParseIceConfig( 1250 const PeerConnectionInterface::RTCConfiguration& config) const { 1251 cricket::IceConfig ice_config; 1252 ice_config.receiving_timeout_ms = config.ice_connection_receiving_timeout; 1253 ice_config.backup_connection_ping_interval = 1254 config.ice_backup_candidate_pair_ping_interval; 1255 ice_config.gather_continually = (config.continual_gathering_policy == 1256 PeerConnectionInterface::GATHER_CONTINUALLY); 1257 return ice_config; 1258} 1259 1260void WebRtcSession::SetIceConfig(const cricket::IceConfig& config) { 1261 transport_controller_->SetIceConfig(config); 1262} 1263 1264void WebRtcSession::MaybeStartGathering() { 1265 transport_controller_->MaybeStartGathering(); 1266} 1267 1268bool WebRtcSession::GetLocalTrackIdBySsrc(uint32_t ssrc, 1269 std::string* track_id) { 1270 if (!local_desc_) { 1271 return false; 1272 } 1273 return webrtc::GetTrackIdBySsrc(local_desc_->description(), ssrc, track_id); 1274} 1275 1276bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32_t ssrc, 1277 std::string* track_id) { 1278 if (!remote_desc_) { 1279 return false; 1280 } 1281 return webrtc::GetTrackIdBySsrc(remote_desc_->description(), ssrc, track_id); 1282} 1283 1284std::string WebRtcSession::BadStateErrMsg(State state) { 1285 std::ostringstream desc; 1286 desc << "Called in wrong state: " << GetStateString(state); 1287 return desc.str(); 1288} 1289 1290void WebRtcSession::SetAudioPlayout(uint32_t ssrc, bool enable) { 1291 ASSERT(signaling_thread()->IsCurrent()); 1292 if (!voice_channel_) { 1293 LOG(LS_ERROR) << "SetAudioPlayout: No audio channel exists."; 1294 return; 1295 } 1296 if (!voice_channel_->SetOutputVolume(ssrc, enable ? 1 : 0)) { 1297 // Allow that SetOutputVolume fail if |enable| is false but assert 1298 // otherwise. This in the normal case when the underlying media channel has 1299 // already been deleted. 1300 ASSERT(enable == false); 1301 } 1302} 1303 1304void WebRtcSession::SetAudioSend(uint32_t ssrc, 1305 bool enable, 1306 const cricket::AudioOptions& options, 1307 cricket::AudioRenderer* renderer) { 1308 ASSERT(signaling_thread()->IsCurrent()); 1309 if (!voice_channel_) { 1310 LOG(LS_ERROR) << "SetAudioSend: No audio channel exists."; 1311 return; 1312 } 1313 if (!voice_channel_->SetAudioSend(ssrc, enable, &options, renderer)) { 1314 LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc; 1315 } 1316} 1317 1318void WebRtcSession::SetAudioPlayoutVolume(uint32_t ssrc, double volume) { 1319 ASSERT(signaling_thread()->IsCurrent()); 1320 ASSERT(volume >= 0 && volume <= 10); 1321 if (!voice_channel_) { 1322 LOG(LS_ERROR) << "SetAudioPlayoutVolume: No audio channel exists."; 1323 return; 1324 } 1325 1326 if (!voice_channel_->SetOutputVolume(ssrc, volume)) { 1327 ASSERT(false); 1328 } 1329} 1330 1331void WebRtcSession::SetRawAudioSink(uint32_t ssrc, 1332 rtc::scoped_ptr<AudioSinkInterface> sink) { 1333 ASSERT(signaling_thread()->IsCurrent()); 1334 if (!voice_channel_) 1335 return; 1336 1337 voice_channel_->SetRawAudioSink(ssrc, std::move(sink)); 1338} 1339 1340bool WebRtcSession::SetCaptureDevice(uint32_t ssrc, 1341 cricket::VideoCapturer* camera) { 1342 ASSERT(signaling_thread()->IsCurrent()); 1343 1344 if (!video_channel_) { 1345 // |video_channel_| doesnt't exist. Probably because the remote end doesnt't 1346 // support video. 1347 LOG(LS_WARNING) << "Video not used in this call."; 1348 return false; 1349 } 1350 if (!video_channel_->SetCapturer(ssrc, camera)) { 1351 // Allow that SetCapturer fail if |camera| is NULL but assert otherwise. 1352 // This in the normal case when the underlying media channel has already 1353 // been deleted. 1354 ASSERT(camera == NULL); 1355 return false; 1356 } 1357 return true; 1358} 1359 1360void WebRtcSession::SetVideoPlayout(uint32_t ssrc, 1361 bool enable, 1362 cricket::VideoRenderer* renderer) { 1363 ASSERT(signaling_thread()->IsCurrent()); 1364 if (!video_channel_) { 1365 LOG(LS_WARNING) << "SetVideoPlayout: No video channel exists."; 1366 return; 1367 } 1368 if (!video_channel_->SetRenderer(ssrc, enable ? renderer : NULL)) { 1369 // Allow that SetRenderer fail if |renderer| is NULL but assert otherwise. 1370 // This in the normal case when the underlying media channel has already 1371 // been deleted. 1372 ASSERT(renderer == NULL); 1373 } 1374} 1375 1376void WebRtcSession::SetVideoSend(uint32_t ssrc, 1377 bool enable, 1378 const cricket::VideoOptions* options) { 1379 ASSERT(signaling_thread()->IsCurrent()); 1380 if (!video_channel_) { 1381 LOG(LS_WARNING) << "SetVideoSend: No video channel exists."; 1382 return; 1383 } 1384 if (!video_channel_->SetVideoSend(ssrc, enable, options)) { 1385 // Allow that MuteStream fail if |enable| is false but assert otherwise. 1386 // This in the normal case when the underlying media channel has already 1387 // been deleted. 1388 ASSERT(enable == false); 1389 } 1390} 1391 1392bool WebRtcSession::CanInsertDtmf(const std::string& track_id) { 1393 ASSERT(signaling_thread()->IsCurrent()); 1394 if (!voice_channel_) { 1395 LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists."; 1396 return false; 1397 } 1398 uint32_t send_ssrc = 0; 1399 // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc 1400 // exists. 1401 if (!local_desc_ || 1402 !GetAudioSsrcByTrackId(local_desc_->description(), track_id, 1403 &send_ssrc)) { 1404 LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id; 1405 return false; 1406 } 1407 return voice_channel_->CanInsertDtmf(); 1408} 1409 1410bool WebRtcSession::InsertDtmf(const std::string& track_id, 1411 int code, int duration) { 1412 ASSERT(signaling_thread()->IsCurrent()); 1413 if (!voice_channel_) { 1414 LOG(LS_ERROR) << "InsertDtmf: No audio channel exists."; 1415 return false; 1416 } 1417 uint32_t send_ssrc = 0; 1418 if (!VERIFY(local_desc_ && GetAudioSsrcByTrackId(local_desc_->description(), 1419 track_id, &send_ssrc))) { 1420 LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id; 1421 return false; 1422 } 1423 if (!voice_channel_->InsertDtmf(send_ssrc, code, duration)) { 1424 LOG(LS_ERROR) << "Failed to insert DTMF to channel."; 1425 return false; 1426 } 1427 return true; 1428} 1429 1430sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() { 1431 return &SignalVoiceChannelDestroyed; 1432} 1433 1434bool WebRtcSession::SendData(const cricket::SendDataParams& params, 1435 const rtc::Buffer& payload, 1436 cricket::SendDataResult* result) { 1437 if (!data_channel_) { 1438 LOG(LS_ERROR) << "SendData called when data_channel_ is NULL."; 1439 return false; 1440 } 1441 return data_channel_->SendData(params, payload, result); 1442} 1443 1444bool WebRtcSession::ConnectDataChannel(DataChannel* webrtc_data_channel) { 1445 if (!data_channel_) { 1446 LOG(LS_ERROR) << "ConnectDataChannel called when data_channel_ is NULL."; 1447 return false; 1448 } 1449 data_channel_->SignalReadyToSendData.connect(webrtc_data_channel, 1450 &DataChannel::OnChannelReady); 1451 data_channel_->SignalDataReceived.connect(webrtc_data_channel, 1452 &DataChannel::OnDataReceived); 1453 data_channel_->SignalStreamClosedRemotely.connect( 1454 webrtc_data_channel, &DataChannel::OnStreamClosedRemotely); 1455 return true; 1456} 1457 1458void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) { 1459 if (!data_channel_) { 1460 LOG(LS_ERROR) << "DisconnectDataChannel called when data_channel_ is NULL."; 1461 return; 1462 } 1463 data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel); 1464 data_channel_->SignalDataReceived.disconnect(webrtc_data_channel); 1465 data_channel_->SignalStreamClosedRemotely.disconnect(webrtc_data_channel); 1466} 1467 1468void WebRtcSession::AddSctpDataStream(int sid) { 1469 if (!data_channel_) { 1470 LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL."; 1471 return; 1472 } 1473 data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid)); 1474 data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid)); 1475} 1476 1477void WebRtcSession::RemoveSctpDataStream(int sid) { 1478 if (!data_channel_) { 1479 LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is " 1480 << "NULL."; 1481 return; 1482 } 1483 data_channel_->RemoveRecvStream(sid); 1484 data_channel_->RemoveSendStream(sid); 1485} 1486 1487bool WebRtcSession::ReadyToSendData() const { 1488 return data_channel_ && data_channel_->ready_to_send_data(); 1489} 1490 1491cricket::DataChannelType WebRtcSession::data_channel_type() const { 1492 return data_channel_type_; 1493} 1494 1495bool WebRtcSession::IceRestartPending() const { 1496 return ice_restart_latch_->Get(); 1497} 1498 1499void WebRtcSession::ResetIceRestartLatch() { 1500 ice_restart_latch_->Reset(); 1501} 1502 1503void WebRtcSession::OnCertificateReady( 1504 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { 1505 transport_controller_->SetLocalCertificate(certificate); 1506} 1507 1508bool WebRtcSession::waiting_for_certificate_for_testing() const { 1509 return webrtc_session_desc_factory_->waiting_for_certificate_for_testing(); 1510} 1511 1512const rtc::scoped_refptr<rtc::RTCCertificate>& 1513WebRtcSession::certificate_for_testing() { 1514 return transport_controller_->certificate_for_testing(); 1515} 1516 1517void WebRtcSession::SetIceConnectionState( 1518 PeerConnectionInterface::IceConnectionState state) { 1519 if (ice_connection_state_ == state) { 1520 return; 1521 } 1522 1523 // ASSERT that the requested transition is allowed. Note that 1524 // WebRtcSession does not implement "kIceConnectionClosed" (that is handled 1525 // within PeerConnection). This switch statement should compile away when 1526 // ASSERTs are disabled. 1527 LOG(LS_INFO) << "Changing IceConnectionState " << ice_connection_state_ 1528 << " => " << state; 1529 switch (ice_connection_state_) { 1530 case PeerConnectionInterface::kIceConnectionNew: 1531 ASSERT(state == PeerConnectionInterface::kIceConnectionChecking); 1532 break; 1533 case PeerConnectionInterface::kIceConnectionChecking: 1534 ASSERT(state == PeerConnectionInterface::kIceConnectionFailed || 1535 state == PeerConnectionInterface::kIceConnectionConnected); 1536 break; 1537 case PeerConnectionInterface::kIceConnectionConnected: 1538 ASSERT(state == PeerConnectionInterface::kIceConnectionDisconnected || 1539 state == PeerConnectionInterface::kIceConnectionChecking || 1540 state == PeerConnectionInterface::kIceConnectionCompleted); 1541 break; 1542 case PeerConnectionInterface::kIceConnectionCompleted: 1543 ASSERT(state == PeerConnectionInterface::kIceConnectionConnected || 1544 state == PeerConnectionInterface::kIceConnectionDisconnected); 1545 break; 1546 case PeerConnectionInterface::kIceConnectionFailed: 1547 ASSERT(state == PeerConnectionInterface::kIceConnectionNew); 1548 break; 1549 case PeerConnectionInterface::kIceConnectionDisconnected: 1550 ASSERT(state == PeerConnectionInterface::kIceConnectionChecking || 1551 state == PeerConnectionInterface::kIceConnectionConnected || 1552 state == PeerConnectionInterface::kIceConnectionCompleted || 1553 state == PeerConnectionInterface::kIceConnectionFailed); 1554 break; 1555 case PeerConnectionInterface::kIceConnectionClosed: 1556 ASSERT(false); 1557 break; 1558 default: 1559 ASSERT(false); 1560 break; 1561 } 1562 1563 ice_connection_state_ = state; 1564 if (ice_observer_) { 1565 ice_observer_->OnIceConnectionChange(ice_connection_state_); 1566 } 1567} 1568 1569void WebRtcSession::OnTransportControllerConnectionState( 1570 cricket::IceConnectionState state) { 1571 switch (state) { 1572 case cricket::kIceConnectionConnecting: 1573 // If the current state is Connected or Completed, then there were 1574 // writable channels but now there are not, so the next state must 1575 // be Disconnected. 1576 // kIceConnectionConnecting is currently used as the default, 1577 // un-connected state by the TransportController, so its only use is 1578 // detecting disconnections. 1579 if (ice_connection_state_ == 1580 PeerConnectionInterface::kIceConnectionConnected || 1581 ice_connection_state_ == 1582 PeerConnectionInterface::kIceConnectionCompleted) { 1583 SetIceConnectionState( 1584 PeerConnectionInterface::kIceConnectionDisconnected); 1585 } 1586 break; 1587 case cricket::kIceConnectionFailed: 1588 SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed); 1589 break; 1590 case cricket::kIceConnectionConnected: 1591 LOG(LS_INFO) << "Changing to ICE connected state because " 1592 << "all transports are writable."; 1593 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected); 1594 break; 1595 case cricket::kIceConnectionCompleted: 1596 LOG(LS_INFO) << "Changing to ICE completed state because " 1597 << "all transports are complete."; 1598 if (ice_connection_state_ != 1599 PeerConnectionInterface::kIceConnectionConnected) { 1600 // If jumping directly from "checking" to "connected", 1601 // signal "connected" first. 1602 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected); 1603 } 1604 SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted); 1605 if (metrics_observer_) { 1606 ReportTransportStats(); 1607 } 1608 break; 1609 default: 1610 ASSERT(false); 1611 } 1612} 1613 1614void WebRtcSession::OnTransportControllerReceiving(bool receiving) { 1615 SetIceConnectionReceiving(receiving); 1616} 1617 1618void WebRtcSession::SetIceConnectionReceiving(bool receiving) { 1619 if (ice_connection_receiving_ == receiving) { 1620 return; 1621 } 1622 ice_connection_receiving_ = receiving; 1623 if (ice_observer_) { 1624 ice_observer_->OnIceConnectionReceivingChange(receiving); 1625 } 1626} 1627 1628void WebRtcSession::OnTransportControllerCandidatesGathered( 1629 const std::string& transport_name, 1630 const cricket::Candidates& candidates) { 1631 ASSERT(signaling_thread()->IsCurrent()); 1632 int sdp_mline_index; 1633 if (!GetLocalCandidateMediaIndex(transport_name, &sdp_mline_index)) { 1634 LOG(LS_ERROR) << "OnTransportControllerCandidatesGathered: content name " 1635 << transport_name << " not found"; 1636 return; 1637 } 1638 1639 for (cricket::Candidates::const_iterator citer = candidates.begin(); 1640 citer != candidates.end(); ++citer) { 1641 // Use transport_name as the candidate media id. 1642 JsepIceCandidate candidate(transport_name, sdp_mline_index, *citer); 1643 if (ice_observer_) { 1644 ice_observer_->OnIceCandidate(&candidate); 1645 } 1646 if (local_desc_) { 1647 local_desc_->AddCandidate(&candidate); 1648 } 1649 } 1650} 1651 1652// Enabling voice and video channel. 1653void WebRtcSession::EnableChannels() { 1654 if (voice_channel_ && !voice_channel_->enabled()) 1655 voice_channel_->Enable(true); 1656 1657 if (video_channel_ && !video_channel_->enabled()) 1658 video_channel_->Enable(true); 1659 1660 if (data_channel_ && !data_channel_->enabled()) 1661 data_channel_->Enable(true); 1662} 1663 1664// Returns the media index for a local ice candidate given the content name. 1665bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name, 1666 int* sdp_mline_index) { 1667 if (!local_desc_ || !sdp_mline_index) { 1668 return false; 1669 } 1670 1671 bool content_found = false; 1672 const ContentInfos& contents = local_desc_->description()->contents(); 1673 for (size_t index = 0; index < contents.size(); ++index) { 1674 if (contents[index].name == content_name) { 1675 *sdp_mline_index = static_cast<int>(index); 1676 content_found = true; 1677 break; 1678 } 1679 } 1680 return content_found; 1681} 1682 1683bool WebRtcSession::UseCandidatesInSessionDescription( 1684 const SessionDescriptionInterface* remote_desc) { 1685 if (!remote_desc) { 1686 return true; 1687 } 1688 bool ret = true; 1689 1690 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) { 1691 const IceCandidateCollection* candidates = remote_desc->candidates(m); 1692 for (size_t n = 0; n < candidates->count(); ++n) { 1693 const IceCandidateInterface* candidate = candidates->at(n); 1694 bool valid = false; 1695 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) { 1696 if (valid) { 1697 LOG(LS_INFO) << "UseCandidatesInSessionDescription: Not ready to use " 1698 << "candidate."; 1699 } 1700 continue; 1701 } 1702 ret = UseCandidate(candidate); 1703 if (!ret) { 1704 break; 1705 } 1706 } 1707 } 1708 return ret; 1709} 1710 1711bool WebRtcSession::UseCandidate( 1712 const IceCandidateInterface* candidate) { 1713 1714 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index()); 1715 size_t remote_content_size = remote_desc_->description()->contents().size(); 1716 if (mediacontent_index >= remote_content_size) { 1717 LOG(LS_ERROR) 1718 << "UseRemoteCandidateInSession: Invalid candidate media index."; 1719 return false; 1720 } 1721 1722 cricket::ContentInfo content = 1723 remote_desc_->description()->contents()[mediacontent_index]; 1724 std::vector<cricket::Candidate> candidates; 1725 candidates.push_back(candidate->candidate()); 1726 // Invoking BaseSession method to handle remote candidates. 1727 std::string error; 1728 if (transport_controller_->AddRemoteCandidates(content.name, candidates, 1729 &error)) { 1730 // Candidates successfully submitted for checking. 1731 if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew || 1732 ice_connection_state_ == 1733 PeerConnectionInterface::kIceConnectionDisconnected) { 1734 // If state is New, then the session has just gotten its first remote ICE 1735 // candidates, so go to Checking. 1736 // If state is Disconnected, the session is re-using old candidates or 1737 // receiving additional ones, so go to Checking. 1738 // If state is Connected, stay Connected. 1739 // TODO(bemasc): If state is Connected, and the new candidates are for a 1740 // newly added transport, then the state actually _should_ move to 1741 // checking. Add a way to distinguish that case. 1742 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking); 1743 } 1744 // TODO(bemasc): If state is Completed, go back to Connected. 1745 } else { 1746 if (!error.empty()) { 1747 LOG(LS_WARNING) << error; 1748 } 1749 } 1750 return true; 1751} 1752 1753void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) { 1754 // Destroy video_channel_ first since it may have a pointer to the 1755 // voice_channel_. 1756 const cricket::ContentInfo* video_info = 1757 cricket::GetFirstVideoContent(desc); 1758 if ((!video_info || video_info->rejected) && video_channel_) { 1759 SignalVideoChannelDestroyed(); 1760 channel_manager_->DestroyVideoChannel(video_channel_.release()); 1761 } 1762 1763 const cricket::ContentInfo* voice_info = 1764 cricket::GetFirstAudioContent(desc); 1765 if ((!voice_info || voice_info->rejected) && voice_channel_) { 1766 SignalVoiceChannelDestroyed(); 1767 channel_manager_->DestroyVoiceChannel(voice_channel_.release()); 1768 } 1769 1770 const cricket::ContentInfo* data_info = 1771 cricket::GetFirstDataContent(desc); 1772 if ((!data_info || data_info->rejected) && data_channel_) { 1773 SignalDataChannelDestroyed(); 1774 channel_manager_->DestroyDataChannel(data_channel_.release()); 1775 } 1776} 1777 1778// TODO(mallinath) - Add a correct error code if the channels are not created 1779// due to BUNDLE is enabled but rtcp-mux is disabled. 1780bool WebRtcSession::CreateChannels(const SessionDescription* desc) { 1781 // Creating the media channels and transport proxies. 1782 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc); 1783 if (voice && !voice->rejected && !voice_channel_) { 1784 if (!CreateVoiceChannel(voice)) { 1785 LOG(LS_ERROR) << "Failed to create voice channel."; 1786 return false; 1787 } 1788 } 1789 1790 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc); 1791 if (video && !video->rejected && !video_channel_) { 1792 if (!CreateVideoChannel(video)) { 1793 LOG(LS_ERROR) << "Failed to create video channel."; 1794 return false; 1795 } 1796 } 1797 1798 const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc); 1799 if (data_channel_type_ != cricket::DCT_NONE && 1800 data && !data->rejected && !data_channel_) { 1801 if (!CreateDataChannel(data)) { 1802 LOG(LS_ERROR) << "Failed to create data channel."; 1803 return false; 1804 } 1805 } 1806 1807 if (rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire) { 1808 if (voice_channel()) { 1809 voice_channel()->ActivateRtcpMux(); 1810 } 1811 if (video_channel()) { 1812 video_channel()->ActivateRtcpMux(); 1813 } 1814 if (data_channel()) { 1815 data_channel()->ActivateRtcpMux(); 1816 } 1817 } 1818 1819 // Enable BUNDLE immediately when kBundlePolicyMaxBundle is in effect. 1820 if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle) { 1821 const cricket::ContentGroup* bundle_group = desc->GetGroupByName( 1822 cricket::GROUP_TYPE_BUNDLE); 1823 if (!bundle_group) { 1824 LOG(LS_WARNING) << "max-bundle specified without BUNDLE specified"; 1825 return false; 1826 } 1827 if (!EnableBundle(*bundle_group)) { 1828 LOG(LS_WARNING) << "max-bundle failed to enable bundling."; 1829 return false; 1830 } 1831 } 1832 1833 return true; 1834} 1835 1836bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) { 1837 voice_channel_.reset(channel_manager_->CreateVoiceChannel( 1838 media_controller_, transport_controller_.get(), content->name, true, 1839 audio_options_)); 1840 if (!voice_channel_) { 1841 return false; 1842 } 1843 1844 voice_channel_->SignalDtlsSetupFailure.connect( 1845 this, &WebRtcSession::OnDtlsSetupFailure); 1846 1847 SignalVoiceChannelCreated(); 1848 voice_channel_->transport_channel()->SignalSentPacket.connect( 1849 this, &WebRtcSession::OnSentPacket_w); 1850 return true; 1851} 1852 1853bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) { 1854 video_channel_.reset(channel_manager_->CreateVideoChannel( 1855 media_controller_, transport_controller_.get(), content->name, true, 1856 video_options_)); 1857 if (!video_channel_) { 1858 return false; 1859 } 1860 1861 video_channel_->SignalDtlsSetupFailure.connect( 1862 this, &WebRtcSession::OnDtlsSetupFailure); 1863 1864 SignalVideoChannelCreated(); 1865 video_channel_->transport_channel()->SignalSentPacket.connect( 1866 this, &WebRtcSession::OnSentPacket_w); 1867 return true; 1868} 1869 1870bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) { 1871 bool sctp = (data_channel_type_ == cricket::DCT_SCTP); 1872 data_channel_.reset(channel_manager_->CreateDataChannel( 1873 transport_controller_.get(), content->name, !sctp, data_channel_type_)); 1874 if (!data_channel_) { 1875 return false; 1876 } 1877 1878 if (sctp) { 1879 data_channel_->SignalDataReceived.connect( 1880 this, &WebRtcSession::OnDataChannelMessageReceived); 1881 } 1882 1883 data_channel_->SignalDtlsSetupFailure.connect( 1884 this, &WebRtcSession::OnDtlsSetupFailure); 1885 1886 SignalDataChannelCreated(); 1887 data_channel_->transport_channel()->SignalSentPacket.connect( 1888 this, &WebRtcSession::OnSentPacket_w); 1889 return true; 1890} 1891 1892void WebRtcSession::OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp) { 1893 SetError(ERROR_TRANSPORT, 1894 rtcp ? kDtlsSetupFailureRtcp : kDtlsSetupFailureRtp); 1895} 1896 1897void WebRtcSession::OnDataChannelMessageReceived( 1898 cricket::DataChannel* channel, 1899 const cricket::ReceiveDataParams& params, 1900 const rtc::Buffer& payload) { 1901 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP); 1902 if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) { 1903 // Received OPEN message; parse and signal that a new data channel should 1904 // be created. 1905 std::string label; 1906 InternalDataChannelInit config; 1907 config.id = params.ssrc; 1908 if (!ParseDataChannelOpenMessage(payload, &label, &config)) { 1909 LOG(LS_WARNING) << "Failed to parse the OPEN message for sid " 1910 << params.ssrc; 1911 return; 1912 } 1913 config.open_handshake_role = InternalDataChannelInit::kAcker; 1914 SignalDataChannelOpenMessage(label, config); 1915 } 1916 // Otherwise ignore the message. 1917} 1918 1919// Returns false if bundle is enabled and rtcp_mux is disabled. 1920bool WebRtcSession::ValidateBundleSettings(const SessionDescription* desc) { 1921 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE); 1922 if (!bundle_enabled) 1923 return true; 1924 1925 const cricket::ContentGroup* bundle_group = 1926 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); 1927 ASSERT(bundle_group != NULL); 1928 1929 const cricket::ContentInfos& contents = desc->contents(); 1930 for (cricket::ContentInfos::const_iterator citer = contents.begin(); 1931 citer != contents.end(); ++citer) { 1932 const cricket::ContentInfo* content = (&*citer); 1933 ASSERT(content != NULL); 1934 if (bundle_group->HasContentName(content->name) && 1935 !content->rejected && content->type == cricket::NS_JINGLE_RTP) { 1936 if (!HasRtcpMuxEnabled(content)) 1937 return false; 1938 } 1939 } 1940 // RTCP-MUX is enabled in all the contents. 1941 return true; 1942} 1943 1944bool WebRtcSession::HasRtcpMuxEnabled( 1945 const cricket::ContentInfo* content) { 1946 const cricket::MediaContentDescription* description = 1947 static_cast<cricket::MediaContentDescription*>(content->description); 1948 return description->rtcp_mux(); 1949} 1950 1951bool WebRtcSession::ValidateSessionDescription( 1952 const SessionDescriptionInterface* sdesc, 1953 cricket::ContentSource source, std::string* err_desc) { 1954 std::string type; 1955 if (error() != ERROR_NONE) { 1956 return BadSdp(source, type, GetSessionErrorMsg(), err_desc); 1957 } 1958 1959 if (!sdesc || !sdesc->description()) { 1960 return BadSdp(source, type, kInvalidSdp, err_desc); 1961 } 1962 1963 type = sdesc->type(); 1964 Action action = GetAction(sdesc->type()); 1965 if (source == cricket::CS_LOCAL) { 1966 if (!ExpectSetLocalDescription(action)) 1967 return BadLocalSdp(type, BadStateErrMsg(state()), err_desc); 1968 } else { 1969 if (!ExpectSetRemoteDescription(action)) 1970 return BadRemoteSdp(type, BadStateErrMsg(state()), err_desc); 1971 } 1972 1973 // Verify crypto settings. 1974 std::string crypto_error; 1975 if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED || 1976 dtls_enabled_) && 1977 !VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) { 1978 return BadSdp(source, type, crypto_error, err_desc); 1979 } 1980 1981 // Verify ice-ufrag and ice-pwd. 1982 if (!VerifyIceUfragPwdPresent(sdesc->description())) { 1983 return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc); 1984 } 1985 1986 if (!ValidateBundleSettings(sdesc->description())) { 1987 return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc); 1988 } 1989 1990 // Verify m-lines in Answer when compared against Offer. 1991 if (action == kAnswer) { 1992 const cricket::SessionDescription* offer_desc = 1993 (source == cricket::CS_LOCAL) ? remote_desc_->description() 1994 : local_desc_->description(); 1995 if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) { 1996 return BadAnswerSdp(source, kMlineMismatch, err_desc); 1997 } 1998 } 1999 2000 return true; 2001} 2002 2003bool WebRtcSession::ExpectSetLocalDescription(Action action) { 2004 return ((action == kOffer && state() == STATE_INIT) || 2005 // update local offer 2006 (action == kOffer && state() == STATE_SENTOFFER) || 2007 // update the current ongoing session. 2008 (action == kOffer && state() == STATE_INPROGRESS) || 2009 // accept remote offer 2010 (action == kAnswer && state() == STATE_RECEIVEDOFFER) || 2011 (action == kAnswer && state() == STATE_SENTPRANSWER) || 2012 (action == kPrAnswer && state() == STATE_RECEIVEDOFFER) || 2013 (action == kPrAnswer && state() == STATE_SENTPRANSWER)); 2014} 2015 2016bool WebRtcSession::ExpectSetRemoteDescription(Action action) { 2017 return ((action == kOffer && state() == STATE_INIT) || 2018 // update remote offer 2019 (action == kOffer && state() == STATE_RECEIVEDOFFER) || 2020 // update the current ongoing session 2021 (action == kOffer && state() == STATE_INPROGRESS) || 2022 // accept local offer 2023 (action == kAnswer && state() == STATE_SENTOFFER) || 2024 (action == kAnswer && state() == STATE_RECEIVEDPRANSWER) || 2025 (action == kPrAnswer && state() == STATE_SENTOFFER) || 2026 (action == kPrAnswer && state() == STATE_RECEIVEDPRANSWER)); 2027} 2028 2029std::string WebRtcSession::GetSessionErrorMsg() { 2030 std::ostringstream desc; 2031 desc << kSessionError << GetErrorCodeString(error()) << ". "; 2032 desc << kSessionErrorDesc << error_desc() << "."; 2033 return desc.str(); 2034} 2035 2036// We need to check the local/remote description for the Transport instead of 2037// the session, because a new Transport added during renegotiation may have 2038// them unset while the session has them set from the previous negotiation. 2039// Not doing so may trigger the auto generation of transport description and 2040// mess up DTLS identity information, ICE credential, etc. 2041bool WebRtcSession::ReadyToUseRemoteCandidate( 2042 const IceCandidateInterface* candidate, 2043 const SessionDescriptionInterface* remote_desc, 2044 bool* valid) { 2045 *valid = true;; 2046 2047 const SessionDescriptionInterface* current_remote_desc = 2048 remote_desc ? remote_desc : remote_desc_.get(); 2049 2050 if (!current_remote_desc) { 2051 return false; 2052 } 2053 2054 size_t mediacontent_index = 2055 static_cast<size_t>(candidate->sdp_mline_index()); 2056 size_t remote_content_size = 2057 current_remote_desc->description()->contents().size(); 2058 if (mediacontent_index >= remote_content_size) { 2059 LOG(LS_ERROR) 2060 << "ReadyToUseRemoteCandidate: Invalid candidate media index."; 2061 2062 *valid = false; 2063 return false; 2064 } 2065 2066 cricket::ContentInfo content = 2067 current_remote_desc->description()->contents()[mediacontent_index]; 2068 cricket::BaseChannel* channel = GetChannel(content.name); 2069 if (!channel) { 2070 return false; 2071 } 2072 2073 return transport_controller_->ReadyForRemoteCandidates( 2074 channel->transport_name()); 2075} 2076 2077void WebRtcSession::OnTransportControllerGatheringState( 2078 cricket::IceGatheringState state) { 2079 ASSERT(signaling_thread()->IsCurrent()); 2080 if (state == cricket::kIceGatheringGathering) { 2081 if (ice_observer_) { 2082 ice_observer_->OnIceGatheringChange( 2083 PeerConnectionInterface::kIceGatheringGathering); 2084 } 2085 } else if (state == cricket::kIceGatheringComplete) { 2086 if (ice_observer_) { 2087 ice_observer_->OnIceGatheringChange( 2088 PeerConnectionInterface::kIceGatheringComplete); 2089 ice_observer_->OnIceComplete(); 2090 } 2091 } 2092} 2093 2094void WebRtcSession::ReportTransportStats() { 2095 // Use a set so we don't report the same stats twice if two channels share 2096 // a transport. 2097 std::set<std::string> transport_names; 2098 if (voice_channel()) { 2099 transport_names.insert(voice_channel()->transport_name()); 2100 } 2101 if (video_channel()) { 2102 transport_names.insert(video_channel()->transport_name()); 2103 } 2104 if (data_channel()) { 2105 transport_names.insert(data_channel()->transport_name()); 2106 } 2107 for (const auto& name : transport_names) { 2108 cricket::TransportStats stats; 2109 if (transport_controller_->GetStats(name, &stats)) { 2110 ReportBestConnectionState(stats); 2111 ReportNegotiatedCiphers(stats); 2112 } 2113 } 2114} 2115// Walk through the ConnectionInfos to gather best connection usage 2116// for IPv4 and IPv6. 2117void WebRtcSession::ReportBestConnectionState( 2118 const cricket::TransportStats& stats) { 2119 RTC_DCHECK(metrics_observer_ != NULL); 2120 for (cricket::TransportChannelStatsList::const_iterator it = 2121 stats.channel_stats.begin(); 2122 it != stats.channel_stats.end(); ++it) { 2123 for (cricket::ConnectionInfos::const_iterator it_info = 2124 it->connection_infos.begin(); 2125 it_info != it->connection_infos.end(); ++it_info) { 2126 if (!it_info->best_connection) { 2127 continue; 2128 } 2129 2130 PeerConnectionEnumCounterType type = kPeerConnectionEnumCounterMax; 2131 const cricket::Candidate& local = it_info->local_candidate; 2132 const cricket::Candidate& remote = it_info->remote_candidate; 2133 2134 // Increment the counter for IceCandidatePairType. 2135 if (local.protocol() == cricket::TCP_PROTOCOL_NAME || 2136 (local.type() == RELAY_PORT_TYPE && 2137 local.relay_protocol() == cricket::TCP_PROTOCOL_NAME)) { 2138 type = kEnumCounterIceCandidatePairTypeTcp; 2139 } else if (local.protocol() == cricket::UDP_PROTOCOL_NAME) { 2140 type = kEnumCounterIceCandidatePairTypeUdp; 2141 } else { 2142 RTC_CHECK(0); 2143 } 2144 metrics_observer_->IncrementEnumCounter( 2145 type, GetIceCandidatePairCounter(local, remote), 2146 kIceCandidatePairMax); 2147 2148 // Increment the counter for IP type. 2149 if (local.address().family() == AF_INET) { 2150 metrics_observer_->IncrementEnumCounter( 2151 kEnumCounterAddressFamily, kBestConnections_IPv4, 2152 kPeerConnectionAddressFamilyCounter_Max); 2153 2154 } else if (local.address().family() == AF_INET6) { 2155 metrics_observer_->IncrementEnumCounter( 2156 kEnumCounterAddressFamily, kBestConnections_IPv6, 2157 kPeerConnectionAddressFamilyCounter_Max); 2158 } else { 2159 RTC_CHECK(0); 2160 } 2161 2162 return; 2163 } 2164 } 2165} 2166 2167void WebRtcSession::ReportNegotiatedCiphers( 2168 const cricket::TransportStats& stats) { 2169 RTC_DCHECK(metrics_observer_ != NULL); 2170 if (!dtls_enabled_ || stats.channel_stats.empty()) { 2171 return; 2172 } 2173 2174 int srtp_crypto_suite = stats.channel_stats[0].srtp_crypto_suite; 2175 int ssl_cipher_suite = stats.channel_stats[0].ssl_cipher_suite; 2176 if (srtp_crypto_suite == rtc::SRTP_INVALID_CRYPTO_SUITE && 2177 ssl_cipher_suite == rtc::TLS_NULL_WITH_NULL_NULL) { 2178 return; 2179 } 2180 2181 PeerConnectionEnumCounterType srtp_counter_type; 2182 PeerConnectionEnumCounterType ssl_counter_type; 2183 if (stats.transport_name == cricket::CN_AUDIO) { 2184 srtp_counter_type = kEnumCounterAudioSrtpCipher; 2185 ssl_counter_type = kEnumCounterAudioSslCipher; 2186 } else if (stats.transport_name == cricket::CN_VIDEO) { 2187 srtp_counter_type = kEnumCounterVideoSrtpCipher; 2188 ssl_counter_type = kEnumCounterVideoSslCipher; 2189 } else if (stats.transport_name == cricket::CN_DATA) { 2190 srtp_counter_type = kEnumCounterDataSrtpCipher; 2191 ssl_counter_type = kEnumCounterDataSslCipher; 2192 } else { 2193 RTC_NOTREACHED(); 2194 return; 2195 } 2196 2197 if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE) { 2198 metrics_observer_->IncrementSparseEnumCounter(srtp_counter_type, 2199 srtp_crypto_suite); 2200 } 2201 if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL) { 2202 metrics_observer_->IncrementSparseEnumCounter(ssl_counter_type, 2203 ssl_cipher_suite); 2204 } 2205} 2206 2207void WebRtcSession::OnSentPacket_w(cricket::TransportChannel* channel, 2208 const rtc::SentPacket& sent_packet) { 2209 RTC_DCHECK(worker_thread()->IsCurrent()); 2210 media_controller_->call_w()->OnSentPacket(sent_packet); 2211} 2212 2213} // namespace webrtc 2214