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 <vector> 34 35 #include "talk/app/webrtc/jsepicecandidate.h" 36 #include "talk/app/webrtc/jsepsessiondescription.h" 37 #include "talk/app/webrtc/mediaconstraintsinterface.h" 38 #include "talk/app/webrtc/mediastreamsignaling.h" 39 #include "talk/app/webrtc/peerconnectioninterface.h" 40 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" 41 #include "talk/media/base/constants.h" 42 #include "talk/media/base/videocapturer.h" 43 #include "talk/session/media/channel.h" 44 #include "talk/session/media/channelmanager.h" 45 #include "talk/session/media/mediasession.h" 46 #include "webrtc/base/basictypes.h" 47 #include "webrtc/base/helpers.h" 48 #include "webrtc/base/logging.h" 49 #include "webrtc/base/stringencode.h" 50 #include "webrtc/base/stringutils.h" 51 52 using cricket::ContentInfo; 53 using cricket::ContentInfos; 54 using cricket::MediaContentDescription; 55 using cricket::SessionDescription; 56 using cricket::TransportInfo; 57 58 namespace webrtc { 59 60 // Error messages 61 const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE " 62 "is enabled."; 63 const char kCreateChannelFailed[] = "Failed to create channels."; 64 const char kInvalidCandidates[] = "Description contains invalid candidates."; 65 const char kInvalidSdp[] = "Invalid session description."; 66 const char kMlineMismatch[] = 67 "Offer and answer descriptions m-lines are not matching. Rejecting answer."; 68 const char kPushDownTDFailed[] = 69 "Failed to push down transport description:"; 70 const char kSdpWithoutDtlsFingerprint[] = 71 "Called with SDP without DTLS fingerprint."; 72 const char kSdpWithoutSdesCrypto[] = 73 "Called with SDP without SDES crypto."; 74 const char kSdpWithoutIceUfragPwd[] = 75 "Called with SDP without ice-ufrag and ice-pwd."; 76 const char kSessionError[] = "Session error code: "; 77 const char kSessionErrorDesc[] = "Session error description: "; 78 const int kMaxUnsignalledRecvStreams = 20; 79 80 // Compares |answer| against |offer|. Comparision is done 81 // for number of m-lines in answer against offer. If matches true will be 82 // returned otherwise false. 83 static bool VerifyMediaDescriptions( 84 const SessionDescription* answer, const SessionDescription* offer) { 85 if (offer->contents().size() != answer->contents().size()) 86 return false; 87 88 for (size_t i = 0; i < offer->contents().size(); ++i) { 89 if ((offer->contents()[i].name) != answer->contents()[i].name) { 90 return false; 91 } 92 const MediaContentDescription* offer_mdesc = 93 static_cast<const MediaContentDescription*>( 94 offer->contents()[i].description); 95 const MediaContentDescription* answer_mdesc = 96 static_cast<const MediaContentDescription*>( 97 answer->contents()[i].description); 98 if (offer_mdesc->type() != answer_mdesc->type()) { 99 return false; 100 } 101 } 102 return true; 103 } 104 105 // Checks that each non-rejected content has SDES crypto keys or a DTLS 106 // fingerprint. Mismatches, such as replying with a DTLS fingerprint to SDES 107 // keys, will be caught in Transport negotiation, and backstopped by Channel's 108 // |secure_required| check. 109 static bool VerifyCrypto(const SessionDescription* desc, 110 bool dtls_enabled, 111 std::string* error) { 112 const ContentInfos& contents = desc->contents(); 113 for (size_t index = 0; index < contents.size(); ++index) { 114 const ContentInfo* cinfo = &contents[index]; 115 if (cinfo->rejected) { 116 continue; 117 } 118 119 // If the content isn't rejected, crypto must be present. 120 const MediaContentDescription* media = 121 static_cast<const MediaContentDescription*>(cinfo->description); 122 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name); 123 if (!media || !tinfo) { 124 // Something is not right. 125 LOG(LS_ERROR) << kInvalidSdp; 126 *error = kInvalidSdp; 127 return false; 128 } 129 if (dtls_enabled) { 130 if (!tinfo->description.identity_fingerprint) { 131 LOG(LS_WARNING) << 132 "Session description must have DTLS fingerprint if DTLS enabled."; 133 *error = kSdpWithoutDtlsFingerprint; 134 return false; 135 } 136 } else { 137 if (media->cryptos().empty()) { 138 LOG(LS_WARNING) << 139 "Session description must have SDES when DTLS disabled."; 140 *error = kSdpWithoutSdesCrypto; 141 return false; 142 } 143 } 144 } 145 146 return true; 147 } 148 149 // Checks that each non-rejected content has ice-ufrag and ice-pwd set. 150 static bool VerifyIceUfragPwdPresent(const SessionDescription* desc) { 151 const ContentInfos& contents = desc->contents(); 152 for (size_t index = 0; index < contents.size(); ++index) { 153 const ContentInfo* cinfo = &contents[index]; 154 if (cinfo->rejected) { 155 continue; 156 } 157 158 // If the content isn't rejected, ice-ufrag and ice-pwd must be present. 159 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name); 160 if (!tinfo) { 161 // Something is not right. 162 LOG(LS_ERROR) << kInvalidSdp; 163 return false; 164 } 165 if (tinfo->description.ice_ufrag.empty() || 166 tinfo->description.ice_pwd.empty()) { 167 LOG(LS_ERROR) << "Session description must have ice ufrag and pwd."; 168 return false; 169 } 170 } 171 return true; 172 } 173 174 // Forces |sdesc->crypto_required| to the appropriate state based on the 175 // current security policy, to ensure a failure occurs if there is an error 176 // in crypto negotiation. 177 // Called when processing the local session description. 178 static void UpdateSessionDescriptionSecurePolicy(cricket::CryptoType type, 179 SessionDescription* sdesc) { 180 if (!sdesc) { 181 return; 182 } 183 184 // Updating the |crypto_required_| in MediaContentDescription to the 185 // appropriate state based on the current security policy. 186 for (cricket::ContentInfos::iterator iter = sdesc->contents().begin(); 187 iter != sdesc->contents().end(); ++iter) { 188 if (cricket::IsMediaContent(&*iter)) { 189 MediaContentDescription* mdesc = 190 static_cast<MediaContentDescription*> (iter->description); 191 if (mdesc) { 192 mdesc->set_crypto_required(type); 193 } 194 } 195 } 196 } 197 198 static bool GetAudioSsrcByTrackId( 199 const SessionDescription* session_description, 200 const std::string& track_id, uint32 *ssrc) { 201 const cricket::ContentInfo* audio_info = 202 cricket::GetFirstAudioContent(session_description); 203 if (!audio_info) { 204 LOG(LS_ERROR) << "Audio not used in this call"; 205 return false; 206 } 207 208 const cricket::MediaContentDescription* audio_content = 209 static_cast<const cricket::MediaContentDescription*>( 210 audio_info->description); 211 cricket::StreamParams stream; 212 if (!cricket::GetStreamByIds(audio_content->streams(), "", track_id, 213 &stream)) { 214 return false; 215 } 216 *ssrc = stream.first_ssrc(); 217 return true; 218 } 219 220 static bool GetTrackIdBySsrc(const SessionDescription* session_description, 221 uint32 ssrc, std::string* track_id) { 222 ASSERT(track_id != NULL); 223 224 cricket::StreamParams stream_out; 225 const cricket::ContentInfo* audio_info = 226 cricket::GetFirstAudioContent(session_description); 227 if (audio_info) { 228 const cricket::MediaContentDescription* audio_content = 229 static_cast<const cricket::MediaContentDescription*>( 230 audio_info->description); 231 232 if (cricket::GetStreamBySsrc(audio_content->streams(), ssrc, &stream_out)) { 233 *track_id = stream_out.id; 234 return true; 235 } 236 } 237 238 const cricket::ContentInfo* video_info = 239 cricket::GetFirstVideoContent(session_description); 240 if (video_info) { 241 const cricket::MediaContentDescription* video_content = 242 static_cast<const cricket::MediaContentDescription*>( 243 video_info->description); 244 245 if (cricket::GetStreamBySsrc(video_content->streams(), ssrc, &stream_out)) { 246 *track_id = stream_out.id; 247 return true; 248 } 249 } 250 return false; 251 } 252 253 static bool BadSdp(const std::string& source, 254 const std::string& type, 255 const std::string& reason, 256 std::string* err_desc) { 257 std::ostringstream desc; 258 desc << "Failed to set " << source << " " << type << " sdp: " << reason; 259 260 if (err_desc) { 261 *err_desc = desc.str(); 262 } 263 LOG(LS_ERROR) << desc.str(); 264 return false; 265 } 266 267 static bool BadSdp(cricket::ContentSource source, 268 const std::string& type, 269 const std::string& reason, 270 std::string* err_desc) { 271 if (source == cricket::CS_LOCAL) { 272 return BadSdp("local", type, reason, err_desc); 273 } else { 274 return BadSdp("remote", type, reason, err_desc); 275 } 276 } 277 278 static bool BadLocalSdp(const std::string& type, 279 const std::string& reason, 280 std::string* err_desc) { 281 return BadSdp(cricket::CS_LOCAL, type, reason, err_desc); 282 } 283 284 static bool BadRemoteSdp(const std::string& type, 285 const std::string& reason, 286 std::string* err_desc) { 287 return BadSdp(cricket::CS_REMOTE, type, reason, err_desc); 288 } 289 290 static bool BadOfferSdp(cricket::ContentSource source, 291 const std::string& reason, 292 std::string* err_desc) { 293 return BadSdp(source, SessionDescriptionInterface::kOffer, reason, err_desc); 294 } 295 296 static bool BadPranswerSdp(cricket::ContentSource source, 297 const std::string& reason, 298 std::string* err_desc) { 299 return BadSdp(source, SessionDescriptionInterface::kPrAnswer, 300 reason, err_desc); 301 } 302 303 static bool BadAnswerSdp(cricket::ContentSource source, 304 const std::string& reason, 305 std::string* err_desc) { 306 return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc); 307 } 308 309 #define GET_STRING_OF_STATE(state) \ 310 case cricket::BaseSession::state: \ 311 result = #state; \ 312 break; 313 314 static std::string GetStateString(cricket::BaseSession::State state) { 315 std::string result; 316 switch (state) { 317 GET_STRING_OF_STATE(STATE_INIT) 318 GET_STRING_OF_STATE(STATE_SENTINITIATE) 319 GET_STRING_OF_STATE(STATE_RECEIVEDINITIATE) 320 GET_STRING_OF_STATE(STATE_SENTPRACCEPT) 321 GET_STRING_OF_STATE(STATE_SENTACCEPT) 322 GET_STRING_OF_STATE(STATE_RECEIVEDPRACCEPT) 323 GET_STRING_OF_STATE(STATE_RECEIVEDACCEPT) 324 GET_STRING_OF_STATE(STATE_SENTMODIFY) 325 GET_STRING_OF_STATE(STATE_RECEIVEDMODIFY) 326 GET_STRING_OF_STATE(STATE_SENTREJECT) 327 GET_STRING_OF_STATE(STATE_RECEIVEDREJECT) 328 GET_STRING_OF_STATE(STATE_SENTREDIRECT) 329 GET_STRING_OF_STATE(STATE_SENTTERMINATE) 330 GET_STRING_OF_STATE(STATE_RECEIVEDTERMINATE) 331 GET_STRING_OF_STATE(STATE_INPROGRESS) 332 GET_STRING_OF_STATE(STATE_DEINIT) 333 default: 334 ASSERT(false); 335 break; 336 } 337 return result; 338 } 339 340 #define GET_STRING_OF_ERROR_CODE(err) \ 341 case cricket::BaseSession::err: \ 342 result = #err; \ 343 break; 344 345 static std::string GetErrorCodeString(cricket::BaseSession::Error err) { 346 std::string result; 347 switch (err) { 348 GET_STRING_OF_ERROR_CODE(ERROR_NONE) 349 GET_STRING_OF_ERROR_CODE(ERROR_TIME) 350 GET_STRING_OF_ERROR_CODE(ERROR_RESPONSE) 351 GET_STRING_OF_ERROR_CODE(ERROR_NETWORK) 352 GET_STRING_OF_ERROR_CODE(ERROR_CONTENT) 353 GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT) 354 default: 355 ASSERT(false); 356 break; 357 } 358 return result; 359 } 360 361 static std::string MakeErrorString(const std::string& error, 362 const std::string& desc) { 363 std::ostringstream ret; 364 ret << error << " " << desc; 365 return ret.str(); 366 } 367 368 static std::string MakeTdErrorString(const std::string& desc) { 369 return MakeErrorString(kPushDownTDFailed, desc); 370 } 371 372 // Set |option| to the highest-priority value of |key| in the optional 373 // constraints if the key is found and has a valid value. 374 template<typename T> 375 static void SetOptionFromOptionalConstraint( 376 const MediaConstraintsInterface* constraints, 377 const std::string& key, cricket::Settable<T>* option) { 378 if (!constraints) { 379 return; 380 } 381 std::string string_value; 382 T value; 383 if (constraints->GetOptional().FindFirst(key, &string_value)) { 384 if (rtc::FromString(string_value, &value)) { 385 option->Set(value); 386 } 387 } 388 } 389 390 uint32 ConvertIceTransportTypeToCandidateFilter( 391 PeerConnectionInterface::IceTransportsType type) { 392 switch (type) { 393 case PeerConnectionInterface::kNone: 394 return cricket::CF_NONE; 395 case PeerConnectionInterface::kRelay: 396 return cricket::CF_RELAY; 397 case PeerConnectionInterface::kNoHost: 398 return (cricket::CF_ALL & ~cricket::CF_HOST); 399 case PeerConnectionInterface::kAll: 400 return cricket::CF_ALL; 401 default: ASSERT(false); 402 } 403 return cricket::CF_NONE; 404 } 405 406 // Help class used to remember if a a remote peer has requested ice restart by 407 // by sending a description with new ice ufrag and password. 408 class IceRestartAnswerLatch { 409 public: 410 IceRestartAnswerLatch() : ice_restart_(false) { } 411 412 // Returns true if CheckForRemoteIceRestart has been called with a new session 413 // description where ice password and ufrag has changed since last time 414 // Reset() was called. 415 bool Get() const { 416 return ice_restart_; 417 } 418 419 void Reset() { 420 if (ice_restart_) { 421 ice_restart_ = false; 422 } 423 } 424 425 void CheckForRemoteIceRestart( 426 const SessionDescriptionInterface* old_desc, 427 const SessionDescriptionInterface* new_desc) { 428 if (!old_desc || new_desc->type() != SessionDescriptionInterface::kOffer) { 429 return; 430 } 431 const SessionDescription* new_sd = new_desc->description(); 432 const SessionDescription* old_sd = old_desc->description(); 433 const ContentInfos& contents = new_sd->contents(); 434 for (size_t index = 0; index < contents.size(); ++index) { 435 const ContentInfo* cinfo = &contents[index]; 436 if (cinfo->rejected) { 437 continue; 438 } 439 // If the content isn't rejected, check if ufrag and password has 440 // changed. 441 const cricket::TransportDescription* new_transport_desc = 442 new_sd->GetTransportDescriptionByName(cinfo->name); 443 const cricket::TransportDescription* old_transport_desc = 444 old_sd->GetTransportDescriptionByName(cinfo->name); 445 if (!new_transport_desc || !old_transport_desc) { 446 // No transport description exist. This is not an ice restart. 447 continue; 448 } 449 if (cricket::IceCredentialsChanged(old_transport_desc->ice_ufrag, 450 old_transport_desc->ice_pwd, 451 new_transport_desc->ice_ufrag, 452 new_transport_desc->ice_pwd)) { 453 LOG(LS_INFO) << "Remote peer request ice restart."; 454 ice_restart_ = true; 455 break; 456 } 457 } 458 } 459 460 private: 461 bool ice_restart_; 462 }; 463 464 WebRtcSession::WebRtcSession( 465 cricket::ChannelManager* channel_manager, 466 rtc::Thread* signaling_thread, 467 rtc::Thread* worker_thread, 468 cricket::PortAllocator* port_allocator, 469 MediaStreamSignaling* mediastream_signaling) 470 : cricket::BaseSession(signaling_thread, worker_thread, port_allocator, 471 rtc::ToString(rtc::CreateRandomId64() & 472 LLONG_MAX), 473 cricket::NS_JINGLE_RTP, false), 474 // RFC 3264: The numeric value of the session id and version in the 475 // o line MUST be representable with a "64 bit signed integer". 476 // Due to this constraint session id |sid_| is max limited to LLONG_MAX. 477 channel_manager_(channel_manager), 478 mediastream_signaling_(mediastream_signaling), 479 ice_observer_(NULL), 480 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew), 481 older_version_remote_peer_(false), 482 dtls_enabled_(false), 483 data_channel_type_(cricket::DCT_NONE), 484 ice_restart_latch_(new IceRestartAnswerLatch) { 485 } 486 487 WebRtcSession::~WebRtcSession() { 488 // Destroy video_channel_ first since it may have a pointer to the 489 // voice_channel_. 490 if (video_channel_.get()) { 491 SignalVideoChannelDestroyed(); 492 channel_manager_->DestroyVideoChannel(video_channel_.release()); 493 } 494 if (voice_channel_.get()) { 495 SignalVoiceChannelDestroyed(); 496 channel_manager_->DestroyVoiceChannel(voice_channel_.release()); 497 } 498 if (data_channel_.get()) { 499 SignalDataChannelDestroyed(); 500 channel_manager_->DestroyDataChannel(data_channel_.release()); 501 } 502 for (size_t i = 0; i < saved_candidates_.size(); ++i) { 503 delete saved_candidates_[i]; 504 } 505 delete identity(); 506 } 507 508 bool WebRtcSession::Initialize( 509 const PeerConnectionFactoryInterface::Options& options, 510 const MediaConstraintsInterface* constraints, 511 DTLSIdentityServiceInterface* dtls_identity_service, 512 PeerConnectionInterface::IceTransportsType ice_transport) { 513 // TODO(perkj): Take |constraints| into consideration. Return false if not all 514 // mandatory constraints can be fulfilled. Note that |constraints| 515 // can be null. 516 bool value; 517 518 if (options.disable_encryption) { 519 dtls_enabled_ = false; 520 } else { 521 // Enable DTLS by default if |dtls_identity_service| is valid. 522 dtls_enabled_ = (dtls_identity_service != NULL); 523 // |constraints| can override the default |dtls_enabled_| value. 524 if (FindConstraint( 525 constraints, 526 MediaConstraintsInterface::kEnableDtlsSrtp, 527 &value, NULL)) { 528 dtls_enabled_ = value; 529 } 530 } 531 532 // Enable creation of RTP data channels if the kEnableRtpDataChannels is set. 533 // It takes precendence over the disable_sctp_data_channels 534 // PeerConnectionFactoryInterface::Options. 535 if (FindConstraint( 536 constraints, MediaConstraintsInterface::kEnableRtpDataChannels, 537 &value, NULL) && value) { 538 LOG(LS_INFO) << "Allowing RTP data engine."; 539 data_channel_type_ = cricket::DCT_RTP; 540 } else { 541 // DTLS has to be enabled to use SCTP. 542 if (!options.disable_sctp_data_channels && dtls_enabled_) { 543 LOG(LS_INFO) << "Allowing SCTP data engine."; 544 data_channel_type_ = cricket::DCT_SCTP; 545 } 546 } 547 if (data_channel_type_ != cricket::DCT_NONE) { 548 mediastream_signaling_->SetDataChannelFactory(this); 549 } 550 551 // Find DSCP constraint. 552 if (FindConstraint( 553 constraints, 554 MediaConstraintsInterface::kEnableDscp, 555 &value, NULL)) { 556 audio_options_.dscp.Set(value); 557 video_options_.dscp.Set(value); 558 } 559 560 // Find Suspend Below Min Bitrate constraint. 561 if (FindConstraint( 562 constraints, 563 MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, 564 &value, 565 NULL)) { 566 video_options_.suspend_below_min_bitrate.Set(value); 567 } 568 569 SetOptionFromOptionalConstraint(constraints, 570 MediaConstraintsInterface::kScreencastMinBitrate, 571 &video_options_.screencast_min_bitrate); 572 573 // Find constraints for cpu overuse detection. 574 SetOptionFromOptionalConstraint(constraints, 575 MediaConstraintsInterface::kCpuUnderuseThreshold, 576 &video_options_.cpu_underuse_threshold); 577 SetOptionFromOptionalConstraint(constraints, 578 MediaConstraintsInterface::kCpuOveruseThreshold, 579 &video_options_.cpu_overuse_threshold); 580 SetOptionFromOptionalConstraint(constraints, 581 MediaConstraintsInterface::kCpuOveruseDetection, 582 &video_options_.cpu_overuse_detection); 583 SetOptionFromOptionalConstraint(constraints, 584 MediaConstraintsInterface::kCpuOveruseEncodeUsage, 585 &video_options_.cpu_overuse_encode_usage); 586 SetOptionFromOptionalConstraint(constraints, 587 MediaConstraintsInterface::kCpuUnderuseEncodeRsdThreshold, 588 &video_options_.cpu_underuse_encode_rsd_threshold); 589 SetOptionFromOptionalConstraint(constraints, 590 MediaConstraintsInterface::kCpuOveruseEncodeRsdThreshold, 591 &video_options_.cpu_overuse_encode_rsd_threshold); 592 593 // Find payload padding constraint. 594 SetOptionFromOptionalConstraint(constraints, 595 MediaConstraintsInterface::kPayloadPadding, 596 &video_options_.use_payload_padding); 597 598 SetOptionFromOptionalConstraint(constraints, 599 MediaConstraintsInterface::kNumUnsignalledRecvStreams, 600 &video_options_.unsignalled_recv_stream_limit); 601 if (video_options_.unsignalled_recv_stream_limit.IsSet()) { 602 int stream_limit; 603 video_options_.unsignalled_recv_stream_limit.Get(&stream_limit); 604 stream_limit = rtc::_min(kMaxUnsignalledRecvStreams, stream_limit); 605 stream_limit = rtc::_max(0, stream_limit); 606 video_options_.unsignalled_recv_stream_limit.Set(stream_limit); 607 } 608 609 SetOptionFromOptionalConstraint(constraints, 610 MediaConstraintsInterface::kHighStartBitrate, 611 &video_options_.video_start_bitrate); 612 613 if (FindConstraint( 614 constraints, 615 MediaConstraintsInterface::kVeryHighBitrate, 616 &value, 617 NULL)) { 618 video_options_.video_highest_bitrate.Set( 619 cricket::VideoOptions::VERY_HIGH); 620 } else if (FindConstraint( 621 constraints, 622 MediaConstraintsInterface::kHighBitrate, 623 &value, 624 NULL)) { 625 video_options_.video_highest_bitrate.Set( 626 cricket::VideoOptions::HIGH); 627 } 628 629 SetOptionFromOptionalConstraint(constraints, 630 MediaConstraintsInterface::kCombinedAudioVideoBwe, 631 &audio_options_.combined_audio_video_bwe); 632 633 const cricket::VideoCodec default_codec( 634 JsepSessionDescription::kDefaultVideoCodecId, 635 JsepSessionDescription::kDefaultVideoCodecName, 636 JsepSessionDescription::kMaxVideoCodecWidth, 637 JsepSessionDescription::kMaxVideoCodecHeight, 638 JsepSessionDescription::kDefaultVideoCodecFramerate, 639 JsepSessionDescription::kDefaultVideoCodecPreference); 640 channel_manager_->SetDefaultVideoEncoderConfig( 641 cricket::VideoEncoderConfig(default_codec)); 642 643 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory( 644 signaling_thread(), 645 channel_manager_, 646 mediastream_signaling_, 647 dtls_identity_service, 648 this, 649 id(), 650 data_channel_type_, 651 dtls_enabled_)); 652 653 webrtc_session_desc_factory_->SignalIdentityReady.connect( 654 this, &WebRtcSession::OnIdentityReady); 655 656 if (options.disable_encryption) { 657 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED); 658 } 659 port_allocator()->set_candidate_filter( 660 ConvertIceTransportTypeToCandidateFilter(ice_transport)); 661 return true; 662 } 663 664 void WebRtcSession::Terminate() { 665 SetState(STATE_RECEIVEDTERMINATE); 666 RemoveUnusedChannelsAndTransports(NULL); 667 ASSERT(voice_channel_.get() == NULL); 668 ASSERT(video_channel_.get() == NULL); 669 ASSERT(data_channel_.get() == NULL); 670 } 671 672 bool WebRtcSession::StartCandidatesAllocation() { 673 // SpeculativelyConnectTransportChannels, will call ConnectChannels method 674 // from TransportProxy to start gathering ice candidates. 675 SpeculativelyConnectAllTransportChannels(); 676 if (!saved_candidates_.empty()) { 677 // If there are saved candidates which arrived before local description is 678 // set, copy those to remote description. 679 CopySavedCandidates(remote_desc_.get()); 680 } 681 // Push remote candidates present in remote description to transport channels. 682 UseCandidatesInSessionDescription(remote_desc_.get()); 683 return true; 684 } 685 686 void WebRtcSession::SetSdesPolicy(cricket::SecurePolicy secure_policy) { 687 webrtc_session_desc_factory_->SetSdesPolicy(secure_policy); 688 } 689 690 cricket::SecurePolicy WebRtcSession::SdesPolicy() const { 691 return webrtc_session_desc_factory_->SdesPolicy(); 692 } 693 694 bool WebRtcSession::GetSslRole(rtc::SSLRole* role) { 695 if (local_description() == NULL || remote_description() == NULL) { 696 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get " 697 << "SSL Role of the session."; 698 return false; 699 } 700 701 // TODO(mallinath) - Return role of each transport, as role may differ from 702 // one another. 703 // In current implementaion we just return the role of first transport in the 704 // transport map. 705 for (cricket::TransportMap::const_iterator iter = transport_proxies().begin(); 706 iter != transport_proxies().end(); ++iter) { 707 if (iter->second->impl()) { 708 return iter->second->impl()->GetSslRole(role); 709 } 710 } 711 return false; 712 } 713 714 void WebRtcSession::CreateOffer( 715 CreateSessionDescriptionObserver* observer, 716 const PeerConnectionInterface::RTCOfferAnswerOptions& options) { 717 webrtc_session_desc_factory_->CreateOffer(observer, options); 718 } 719 720 void WebRtcSession::CreateAnswer(CreateSessionDescriptionObserver* observer, 721 const MediaConstraintsInterface* constraints) { 722 webrtc_session_desc_factory_->CreateAnswer(observer, constraints); 723 } 724 725 bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc, 726 std::string* err_desc) { 727 // Takes the ownership of |desc| regardless of the result. 728 rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc); 729 730 // Validate SDP. 731 if (!ValidateSessionDescription(desc, cricket::CS_LOCAL, err_desc)) { 732 return false; 733 } 734 735 // Update the initiator flag if this session is the initiator. 736 Action action = GetAction(desc->type()); 737 if (state() == STATE_INIT && action == kOffer) { 738 set_initiator(true); 739 } 740 741 cricket::SecurePolicy sdes_policy = 742 webrtc_session_desc_factory_->SdesPolicy(); 743 cricket::CryptoType crypto_required = dtls_enabled_ ? 744 cricket::CT_DTLS : (sdes_policy == cricket::SEC_REQUIRED ? 745 cricket::CT_SDES : cricket::CT_NONE); 746 // Update the MediaContentDescription crypto settings as per the policy set. 747 UpdateSessionDescriptionSecurePolicy(crypto_required, desc->description()); 748 749 set_local_description(desc->description()->Copy()); 750 local_desc_.reset(desc_temp.release()); 751 752 // Transport and Media channels will be created only when offer is set. 753 if (action == kOffer && !CreateChannels(local_desc_->description())) { 754 // TODO(mallinath) - Handle CreateChannel failure, as new local description 755 // is applied. Restore back to old description. 756 return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc); 757 } 758 759 // Remove channel and transport proxies, if MediaContentDescription is 760 // rejected. 761 RemoveUnusedChannelsAndTransports(local_desc_->description()); 762 763 if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) { 764 return false; 765 } 766 767 // Kick starting the ice candidates allocation. 768 StartCandidatesAllocation(); 769 770 // Update state and SSRC of local MediaStreams and DataChannels based on the 771 // local session description. 772 mediastream_signaling_->OnLocalDescriptionChanged(local_desc_.get()); 773 774 rtc::SSLRole role; 775 if (data_channel_type_ == cricket::DCT_SCTP && GetSslRole(&role)) { 776 mediastream_signaling_->OnDtlsRoleReadyForSctp(role); 777 } 778 if (error() != cricket::BaseSession::ERROR_NONE) { 779 return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc); 780 } 781 return true; 782 } 783 784 bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc, 785 std::string* err_desc) { 786 // Takes the ownership of |desc| regardless of the result. 787 rtc::scoped_ptr<SessionDescriptionInterface> desc_temp(desc); 788 789 // Validate SDP. 790 if (!ValidateSessionDescription(desc, cricket::CS_REMOTE, err_desc)) { 791 return false; 792 } 793 794 // Transport and Media channels will be created only when offer is set. 795 Action action = GetAction(desc->type()); 796 if (action == kOffer && !CreateChannels(desc->description())) { 797 // TODO(mallinath) - Handle CreateChannel failure, as new local description 798 // is applied. Restore back to old description. 799 return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc); 800 } 801 802 // Remove channel and transport proxies, if MediaContentDescription is 803 // rejected. 804 RemoveUnusedChannelsAndTransports(desc->description()); 805 806 // NOTE: Candidates allocation will be initiated only when SetLocalDescription 807 // is called. 808 set_remote_description(desc->description()->Copy()); 809 if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) { 810 return false; 811 } 812 813 // Update remote MediaStreams. 814 mediastream_signaling_->OnRemoteDescriptionChanged(desc); 815 if (local_description() && !UseCandidatesInSessionDescription(desc)) { 816 return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc); 817 } 818 819 // Copy all saved candidates. 820 CopySavedCandidates(desc); 821 // We retain all received candidates. 822 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( 823 remote_desc_.get(), desc); 824 // Check if this new SessionDescription contains new ice ufrag and password 825 // that indicates the remote peer requests ice restart. 826 ice_restart_latch_->CheckForRemoteIceRestart(remote_desc_.get(), 827 desc); 828 remote_desc_.reset(desc_temp.release()); 829 830 rtc::SSLRole role; 831 if (data_channel_type_ == cricket::DCT_SCTP && GetSslRole(&role)) { 832 mediastream_signaling_->OnDtlsRoleReadyForSctp(role); 833 } 834 835 if (error() != cricket::BaseSession::ERROR_NONE) { 836 return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc); 837 } 838 return true; 839 } 840 841 bool WebRtcSession::UpdateSessionState( 842 Action action, cricket::ContentSource source, 843 std::string* err_desc) { 844 // If there's already a pending error then no state transition should happen. 845 // But all call-sites should be verifying this before calling us! 846 ASSERT(error() == cricket::BaseSession::ERROR_NONE); 847 std::string td_err; 848 if (action == kOffer) { 849 if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) { 850 return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc); 851 } 852 SetState(source == cricket::CS_LOCAL ? 853 STATE_SENTINITIATE : STATE_RECEIVEDINITIATE); 854 if (error() != cricket::BaseSession::ERROR_NONE) { 855 return BadOfferSdp(source, GetSessionErrorMsg(), err_desc); 856 } 857 } else if (action == kPrAnswer) { 858 if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) { 859 return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc); 860 } 861 EnableChannels(); 862 SetState(source == cricket::CS_LOCAL ? 863 STATE_SENTPRACCEPT : STATE_RECEIVEDPRACCEPT); 864 if (error() != cricket::BaseSession::ERROR_NONE) { 865 return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc); 866 } 867 } else if (action == kAnswer) { 868 if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) { 869 return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc); 870 } 871 MaybeEnableMuxingSupport(); 872 EnableChannels(); 873 SetState(source == cricket::CS_LOCAL ? 874 STATE_SENTACCEPT : STATE_RECEIVEDACCEPT); 875 if (error() != cricket::BaseSession::ERROR_NONE) { 876 return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc); 877 } 878 } 879 return true; 880 } 881 882 WebRtcSession::Action WebRtcSession::GetAction(const std::string& type) { 883 if (type == SessionDescriptionInterface::kOffer) { 884 return WebRtcSession::kOffer; 885 } else if (type == SessionDescriptionInterface::kPrAnswer) { 886 return WebRtcSession::kPrAnswer; 887 } else if (type == SessionDescriptionInterface::kAnswer) { 888 return WebRtcSession::kAnswer; 889 } 890 ASSERT(false && "unknown action type"); 891 return WebRtcSession::kOffer; 892 } 893 894 bool WebRtcSession::ProcessIceMessage(const IceCandidateInterface* candidate) { 895 if (state() == STATE_INIT) { 896 LOG(LS_ERROR) << "ProcessIceMessage: ICE candidates can't be added " 897 << "without any offer (local or remote) " 898 << "session description."; 899 return false; 900 } 901 902 if (!candidate) { 903 LOG(LS_ERROR) << "ProcessIceMessage: Candidate is NULL"; 904 return false; 905 } 906 907 bool valid = false; 908 if (!ReadyToUseRemoteCandidate(candidate, NULL, &valid)) { 909 if (valid) { 910 LOG(LS_INFO) << "ProcessIceMessage: Candidate saved"; 911 saved_candidates_.push_back( 912 new JsepIceCandidate(candidate->sdp_mid(), 913 candidate->sdp_mline_index(), 914 candidate->candidate())); 915 } 916 return valid; 917 } 918 919 // Add this candidate to the remote session description. 920 if (!remote_desc_->AddCandidate(candidate)) { 921 LOG(LS_ERROR) << "ProcessIceMessage: Candidate cannot be used"; 922 return false; 923 } 924 925 return UseCandidate(candidate); 926 } 927 928 bool WebRtcSession::SetIceTransports( 929 PeerConnectionInterface::IceTransportsType type) { 930 return port_allocator()->set_candidate_filter( 931 ConvertIceTransportTypeToCandidateFilter(type)); 932 } 933 934 bool WebRtcSession::GetLocalTrackIdBySsrc(uint32 ssrc, std::string* track_id) { 935 if (!BaseSession::local_description()) 936 return false; 937 return webrtc::GetTrackIdBySsrc( 938 BaseSession::local_description(), ssrc, track_id); 939 } 940 941 bool WebRtcSession::GetRemoteTrackIdBySsrc(uint32 ssrc, std::string* track_id) { 942 if (!BaseSession::remote_description()) 943 return false; 944 return webrtc::GetTrackIdBySsrc( 945 BaseSession::remote_description(), ssrc, track_id); 946 } 947 948 std::string WebRtcSession::BadStateErrMsg(State state) { 949 std::ostringstream desc; 950 desc << "Called in wrong state: " << GetStateString(state); 951 return desc.str(); 952 } 953 954 void WebRtcSession::SetAudioPlayout(uint32 ssrc, bool enable, 955 cricket::AudioRenderer* renderer) { 956 ASSERT(signaling_thread()->IsCurrent()); 957 if (!voice_channel_) { 958 LOG(LS_ERROR) << "SetAudioPlayout: No audio channel exists."; 959 return; 960 } 961 if (!voice_channel_->SetRemoteRenderer(ssrc, renderer)) { 962 // SetRenderer() can fail if the ssrc does not match any playout channel. 963 LOG(LS_ERROR) << "SetAudioPlayout: ssrc is incorrect: " << ssrc; 964 return; 965 } 966 if (!voice_channel_->SetOutputScaling(ssrc, enable ? 1 : 0, enable ? 1 : 0)) { 967 // Allow that SetOutputScaling fail if |enable| is false but assert 968 // otherwise. This in the normal case when the underlying media channel has 969 // already been deleted. 970 ASSERT(enable == false); 971 } 972 } 973 974 void WebRtcSession::SetAudioSend(uint32 ssrc, bool enable, 975 const cricket::AudioOptions& options, 976 cricket::AudioRenderer* renderer) { 977 ASSERT(signaling_thread()->IsCurrent()); 978 if (!voice_channel_) { 979 LOG(LS_ERROR) << "SetAudioSend: No audio channel exists."; 980 return; 981 } 982 if (!voice_channel_->SetLocalRenderer(ssrc, renderer)) { 983 // SetRenderer() can fail if the ssrc does not match any send channel. 984 LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc; 985 return; 986 } 987 if (!voice_channel_->MuteStream(ssrc, !enable)) { 988 // Allow that MuteStream fail if |enable| is false but assert otherwise. 989 // This in the normal case when the underlying media channel has already 990 // been deleted. 991 ASSERT(enable == false); 992 return; 993 } 994 if (enable) 995 voice_channel_->SetChannelOptions(options); 996 } 997 998 void WebRtcSession::SetAudioPlayoutVolume(uint32 ssrc, double volume) { 999 ASSERT(signaling_thread()->IsCurrent()); 1000 ASSERT(volume >= 0 && volume <= 10); 1001 if (!voice_channel_) { 1002 LOG(LS_ERROR) << "SetAudioPlayoutVolume: No audio channel exists."; 1003 return; 1004 } 1005 1006 if (!voice_channel_->SetOutputScaling(ssrc, volume, volume)) 1007 ASSERT(false); 1008 } 1009 1010 bool WebRtcSession::SetCaptureDevice(uint32 ssrc, 1011 cricket::VideoCapturer* camera) { 1012 ASSERT(signaling_thread()->IsCurrent()); 1013 1014 if (!video_channel_.get()) { 1015 // |video_channel_| doesnt't exist. Probably because the remote end doesnt't 1016 // support video. 1017 LOG(LS_WARNING) << "Video not used in this call."; 1018 return false; 1019 } 1020 if (!video_channel_->SetCapturer(ssrc, camera)) { 1021 // Allow that SetCapturer fail if |camera| is NULL but assert otherwise. 1022 // This in the normal case when the underlying media channel has already 1023 // been deleted. 1024 ASSERT(camera == NULL); 1025 return false; 1026 } 1027 return true; 1028 } 1029 1030 void WebRtcSession::SetVideoPlayout(uint32 ssrc, 1031 bool enable, 1032 cricket::VideoRenderer* renderer) { 1033 ASSERT(signaling_thread()->IsCurrent()); 1034 if (!video_channel_) { 1035 LOG(LS_WARNING) << "SetVideoPlayout: No video channel exists."; 1036 return; 1037 } 1038 if (!video_channel_->SetRenderer(ssrc, enable ? renderer : NULL)) { 1039 // Allow that SetRenderer fail if |renderer| is NULL but assert otherwise. 1040 // This in the normal case when the underlying media channel has already 1041 // been deleted. 1042 ASSERT(renderer == NULL); 1043 } 1044 } 1045 1046 void WebRtcSession::SetVideoSend(uint32 ssrc, bool enable, 1047 const cricket::VideoOptions* options) { 1048 ASSERT(signaling_thread()->IsCurrent()); 1049 if (!video_channel_) { 1050 LOG(LS_WARNING) << "SetVideoSend: No video channel exists."; 1051 return; 1052 } 1053 if (!video_channel_->MuteStream(ssrc, !enable)) { 1054 // Allow that MuteStream fail if |enable| is false but assert otherwise. 1055 // This in the normal case when the underlying media channel has already 1056 // been deleted. 1057 ASSERT(enable == false); 1058 return; 1059 } 1060 if (enable && options) 1061 video_channel_->SetChannelOptions(*options); 1062 } 1063 1064 bool WebRtcSession::CanInsertDtmf(const std::string& track_id) { 1065 ASSERT(signaling_thread()->IsCurrent()); 1066 if (!voice_channel_) { 1067 LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists."; 1068 return false; 1069 } 1070 uint32 send_ssrc = 0; 1071 // The Dtmf is negotiated per channel not ssrc, so we only check if the ssrc 1072 // exists. 1073 if (!GetAudioSsrcByTrackId(BaseSession::local_description(), track_id, 1074 &send_ssrc)) { 1075 LOG(LS_ERROR) << "CanInsertDtmf: Track does not exist: " << track_id; 1076 return false; 1077 } 1078 return voice_channel_->CanInsertDtmf(); 1079 } 1080 1081 bool WebRtcSession::InsertDtmf(const std::string& track_id, 1082 int code, int duration) { 1083 ASSERT(signaling_thread()->IsCurrent()); 1084 if (!voice_channel_) { 1085 LOG(LS_ERROR) << "InsertDtmf: No audio channel exists."; 1086 return false; 1087 } 1088 uint32 send_ssrc = 0; 1089 if (!VERIFY(GetAudioSsrcByTrackId(BaseSession::local_description(), 1090 track_id, &send_ssrc))) { 1091 LOG(LS_ERROR) << "InsertDtmf: Track does not exist: " << track_id; 1092 return false; 1093 } 1094 if (!voice_channel_->InsertDtmf(send_ssrc, code, duration, 1095 cricket::DF_SEND)) { 1096 LOG(LS_ERROR) << "Failed to insert DTMF to channel."; 1097 return false; 1098 } 1099 return true; 1100 } 1101 1102 sigslot::signal0<>* WebRtcSession::GetOnDestroyedSignal() { 1103 return &SignalVoiceChannelDestroyed; 1104 } 1105 1106 bool WebRtcSession::SendData(const cricket::SendDataParams& params, 1107 const rtc::Buffer& payload, 1108 cricket::SendDataResult* result) { 1109 if (!data_channel_.get()) { 1110 LOG(LS_ERROR) << "SendData called when data_channel_ is NULL."; 1111 return false; 1112 } 1113 return data_channel_->SendData(params, payload, result); 1114 } 1115 1116 bool WebRtcSession::ConnectDataChannel(DataChannel* webrtc_data_channel) { 1117 if (!data_channel_.get()) { 1118 LOG(LS_ERROR) << "ConnectDataChannel called when data_channel_ is NULL."; 1119 return false; 1120 } 1121 data_channel_->SignalReadyToSendData.connect(webrtc_data_channel, 1122 &DataChannel::OnChannelReady); 1123 data_channel_->SignalDataReceived.connect(webrtc_data_channel, 1124 &DataChannel::OnDataReceived); 1125 return true; 1126 } 1127 1128 void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) { 1129 if (!data_channel_.get()) { 1130 LOG(LS_ERROR) << "DisconnectDataChannel called when data_channel_ is NULL."; 1131 return; 1132 } 1133 data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel); 1134 data_channel_->SignalDataReceived.disconnect(webrtc_data_channel); 1135 } 1136 1137 void WebRtcSession::AddSctpDataStream(uint32 sid) { 1138 if (!data_channel_.get()) { 1139 LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL."; 1140 return; 1141 } 1142 data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid)); 1143 data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid)); 1144 } 1145 1146 void WebRtcSession::RemoveSctpDataStream(uint32 sid) { 1147 mediastream_signaling_->RemoveSctpDataChannel(static_cast<int>(sid)); 1148 1149 if (!data_channel_.get()) { 1150 LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is " 1151 << "NULL."; 1152 return; 1153 } 1154 data_channel_->RemoveRecvStream(sid); 1155 data_channel_->RemoveSendStream(sid); 1156 } 1157 1158 bool WebRtcSession::ReadyToSendData() const { 1159 return data_channel_.get() && data_channel_->ready_to_send_data(); 1160 } 1161 1162 rtc::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel( 1163 const std::string& label, 1164 const InternalDataChannelInit* config) { 1165 if (state() == STATE_RECEIVEDTERMINATE) { 1166 return NULL; 1167 } 1168 if (data_channel_type_ == cricket::DCT_NONE) { 1169 LOG(LS_ERROR) << "CreateDataChannel: Data is not supported in this call."; 1170 return NULL; 1171 } 1172 InternalDataChannelInit new_config = 1173 config ? (*config) : InternalDataChannelInit(); 1174 if (data_channel_type_ == cricket::DCT_SCTP) { 1175 if (new_config.id < 0) { 1176 rtc::SSLRole role; 1177 if (GetSslRole(&role) && 1178 !mediastream_signaling_->AllocateSctpSid(role, &new_config.id)) { 1179 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel."; 1180 return NULL; 1181 } 1182 } else if (!mediastream_signaling_->IsSctpSidAvailable(new_config.id)) { 1183 LOG(LS_ERROR) << "Failed to create a SCTP data channel " 1184 << "because the id is already in use or out of range."; 1185 return NULL; 1186 } 1187 } 1188 1189 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create( 1190 this, data_channel_type_, label, new_config)); 1191 if (channel && !mediastream_signaling_->AddDataChannel(channel)) 1192 return NULL; 1193 1194 return channel; 1195 } 1196 1197 cricket::DataChannelType WebRtcSession::data_channel_type() const { 1198 return data_channel_type_; 1199 } 1200 1201 bool WebRtcSession::IceRestartPending() const { 1202 return ice_restart_latch_->Get(); 1203 } 1204 1205 void WebRtcSession::ResetIceRestartLatch() { 1206 ice_restart_latch_->Reset(); 1207 } 1208 1209 void WebRtcSession::OnIdentityReady(rtc::SSLIdentity* identity) { 1210 SetIdentity(identity); 1211 } 1212 1213 bool WebRtcSession::waiting_for_identity() const { 1214 return webrtc_session_desc_factory_->waiting_for_identity(); 1215 } 1216 1217 void WebRtcSession::SetIceConnectionState( 1218 PeerConnectionInterface::IceConnectionState state) { 1219 if (ice_connection_state_ == state) { 1220 return; 1221 } 1222 1223 // ASSERT that the requested transition is allowed. Note that 1224 // WebRtcSession does not implement "kIceConnectionClosed" (that is handled 1225 // within PeerConnection). This switch statement should compile away when 1226 // ASSERTs are disabled. 1227 switch (ice_connection_state_) { 1228 case PeerConnectionInterface::kIceConnectionNew: 1229 ASSERT(state == PeerConnectionInterface::kIceConnectionChecking); 1230 break; 1231 case PeerConnectionInterface::kIceConnectionChecking: 1232 ASSERT(state == PeerConnectionInterface::kIceConnectionFailed || 1233 state == PeerConnectionInterface::kIceConnectionConnected); 1234 break; 1235 case PeerConnectionInterface::kIceConnectionConnected: 1236 ASSERT(state == PeerConnectionInterface::kIceConnectionDisconnected || 1237 state == PeerConnectionInterface::kIceConnectionChecking || 1238 state == PeerConnectionInterface::kIceConnectionCompleted); 1239 break; 1240 case PeerConnectionInterface::kIceConnectionCompleted: 1241 ASSERT(state == PeerConnectionInterface::kIceConnectionConnected || 1242 state == PeerConnectionInterface::kIceConnectionDisconnected); 1243 break; 1244 case PeerConnectionInterface::kIceConnectionFailed: 1245 ASSERT(state == PeerConnectionInterface::kIceConnectionNew); 1246 break; 1247 case PeerConnectionInterface::kIceConnectionDisconnected: 1248 ASSERT(state == PeerConnectionInterface::kIceConnectionChecking || 1249 state == PeerConnectionInterface::kIceConnectionConnected || 1250 state == PeerConnectionInterface::kIceConnectionCompleted || 1251 state == PeerConnectionInterface::kIceConnectionFailed); 1252 break; 1253 case PeerConnectionInterface::kIceConnectionClosed: 1254 ASSERT(false); 1255 break; 1256 default: 1257 ASSERT(false); 1258 break; 1259 } 1260 1261 ice_connection_state_ = state; 1262 if (ice_observer_) { 1263 ice_observer_->OnIceConnectionChange(ice_connection_state_); 1264 } 1265 } 1266 1267 void WebRtcSession::OnTransportRequestSignaling( 1268 cricket::Transport* transport) { 1269 ASSERT(signaling_thread()->IsCurrent()); 1270 transport->OnSignalingReady(); 1271 if (ice_observer_) { 1272 ice_observer_->OnIceGatheringChange( 1273 PeerConnectionInterface::kIceGatheringGathering); 1274 } 1275 } 1276 1277 void WebRtcSession::OnTransportConnecting(cricket::Transport* transport) { 1278 ASSERT(signaling_thread()->IsCurrent()); 1279 // start monitoring for the write state of the transport. 1280 OnTransportWritable(transport); 1281 } 1282 1283 void WebRtcSession::OnTransportWritable(cricket::Transport* transport) { 1284 ASSERT(signaling_thread()->IsCurrent()); 1285 if (transport->all_channels_writable()) { 1286 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected); 1287 } else if (transport->HasChannels()) { 1288 // If the current state is Connected or Completed, then there were writable 1289 // channels but now there are not, so the next state must be Disconnected. 1290 if (ice_connection_state_ == 1291 PeerConnectionInterface::kIceConnectionConnected || 1292 ice_connection_state_ == 1293 PeerConnectionInterface::kIceConnectionCompleted) { 1294 SetIceConnectionState( 1295 PeerConnectionInterface::kIceConnectionDisconnected); 1296 } 1297 } 1298 } 1299 1300 void WebRtcSession::OnTransportCompleted(cricket::Transport* transport) { 1301 ASSERT(signaling_thread()->IsCurrent()); 1302 SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted); 1303 } 1304 1305 void WebRtcSession::OnTransportFailed(cricket::Transport* transport) { 1306 ASSERT(signaling_thread()->IsCurrent()); 1307 SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed); 1308 } 1309 1310 void WebRtcSession::OnTransportProxyCandidatesReady( 1311 cricket::TransportProxy* proxy, const cricket::Candidates& candidates) { 1312 ASSERT(signaling_thread()->IsCurrent()); 1313 ProcessNewLocalCandidate(proxy->content_name(), candidates); 1314 } 1315 1316 void WebRtcSession::OnCandidatesAllocationDone() { 1317 ASSERT(signaling_thread()->IsCurrent()); 1318 if (ice_observer_) { 1319 ice_observer_->OnIceGatheringChange( 1320 PeerConnectionInterface::kIceGatheringComplete); 1321 ice_observer_->OnIceComplete(); 1322 } 1323 } 1324 1325 // Enabling voice and video channel. 1326 void WebRtcSession::EnableChannels() { 1327 if (voice_channel_ && !voice_channel_->enabled()) 1328 voice_channel_->Enable(true); 1329 1330 if (video_channel_ && !video_channel_->enabled()) 1331 video_channel_->Enable(true); 1332 1333 if (data_channel_.get() && !data_channel_->enabled()) 1334 data_channel_->Enable(true); 1335 } 1336 1337 void WebRtcSession::ProcessNewLocalCandidate( 1338 const std::string& content_name, 1339 const cricket::Candidates& candidates) { 1340 int sdp_mline_index; 1341 if (!GetLocalCandidateMediaIndex(content_name, &sdp_mline_index)) { 1342 LOG(LS_ERROR) << "ProcessNewLocalCandidate: content name " 1343 << content_name << " not found"; 1344 return; 1345 } 1346 1347 for (cricket::Candidates::const_iterator citer = candidates.begin(); 1348 citer != candidates.end(); ++citer) { 1349 // Use content_name as the candidate media id. 1350 JsepIceCandidate candidate(content_name, sdp_mline_index, *citer); 1351 if (ice_observer_) { 1352 ice_observer_->OnIceCandidate(&candidate); 1353 } 1354 if (local_desc_) { 1355 local_desc_->AddCandidate(&candidate); 1356 } 1357 } 1358 } 1359 1360 // Returns the media index for a local ice candidate given the content name. 1361 bool WebRtcSession::GetLocalCandidateMediaIndex(const std::string& content_name, 1362 int* sdp_mline_index) { 1363 if (!BaseSession::local_description() || !sdp_mline_index) 1364 return false; 1365 1366 bool content_found = false; 1367 const ContentInfos& contents = BaseSession::local_description()->contents(); 1368 for (size_t index = 0; index < contents.size(); ++index) { 1369 if (contents[index].name == content_name) { 1370 *sdp_mline_index = static_cast<int>(index); 1371 content_found = true; 1372 break; 1373 } 1374 } 1375 return content_found; 1376 } 1377 1378 bool WebRtcSession::UseCandidatesInSessionDescription( 1379 const SessionDescriptionInterface* remote_desc) { 1380 if (!remote_desc) 1381 return true; 1382 bool ret = true; 1383 1384 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) { 1385 const IceCandidateCollection* candidates = remote_desc->candidates(m); 1386 for (size_t n = 0; n < candidates->count(); ++n) { 1387 const IceCandidateInterface* candidate = candidates->at(n); 1388 bool valid = false; 1389 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) { 1390 if (valid) { 1391 LOG(LS_INFO) << "UseCandidatesInSessionDescription: Candidate saved."; 1392 saved_candidates_.push_back( 1393 new JsepIceCandidate(candidate->sdp_mid(), 1394 candidate->sdp_mline_index(), 1395 candidate->candidate())); 1396 } 1397 continue; 1398 } 1399 1400 ret = UseCandidate(candidate); 1401 if (!ret) 1402 break; 1403 } 1404 } 1405 return ret; 1406 } 1407 1408 bool WebRtcSession::UseCandidate( 1409 const IceCandidateInterface* candidate) { 1410 1411 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index()); 1412 size_t remote_content_size = 1413 BaseSession::remote_description()->contents().size(); 1414 if (mediacontent_index >= remote_content_size) { 1415 LOG(LS_ERROR) 1416 << "UseRemoteCandidateInSession: Invalid candidate media index."; 1417 return false; 1418 } 1419 1420 cricket::ContentInfo content = 1421 BaseSession::remote_description()->contents()[mediacontent_index]; 1422 std::vector<cricket::Candidate> candidates; 1423 candidates.push_back(candidate->candidate()); 1424 // Invoking BaseSession method to handle remote candidates. 1425 std::string error; 1426 if (OnRemoteCandidates(content.name, candidates, &error)) { 1427 // Candidates successfully submitted for checking. 1428 if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew || 1429 ice_connection_state_ == 1430 PeerConnectionInterface::kIceConnectionDisconnected) { 1431 // If state is New, then the session has just gotten its first remote ICE 1432 // candidates, so go to Checking. 1433 // If state is Disconnected, the session is re-using old candidates or 1434 // receiving additional ones, so go to Checking. 1435 // If state is Connected, stay Connected. 1436 // TODO(bemasc): If state is Connected, and the new candidates are for a 1437 // newly added transport, then the state actually _should_ move to 1438 // checking. Add a way to distinguish that case. 1439 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking); 1440 } 1441 // TODO(bemasc): If state is Completed, go back to Connected. 1442 } else { 1443 if (!error.empty()) { 1444 LOG(LS_WARNING) << error; 1445 } 1446 } 1447 return true; 1448 } 1449 1450 void WebRtcSession::RemoveUnusedChannelsAndTransports( 1451 const SessionDescription* desc) { 1452 // Destroy video_channel_ first since it may have a pointer to the 1453 // voice_channel_. 1454 const cricket::ContentInfo* video_info = 1455 cricket::GetFirstVideoContent(desc); 1456 if ((!video_info || video_info->rejected) && video_channel_) { 1457 mediastream_signaling_->OnVideoChannelClose(); 1458 SignalVideoChannelDestroyed(); 1459 const std::string content_name = video_channel_->content_name(); 1460 channel_manager_->DestroyVideoChannel(video_channel_.release()); 1461 DestroyTransportProxy(content_name); 1462 } 1463 1464 const cricket::ContentInfo* voice_info = 1465 cricket::GetFirstAudioContent(desc); 1466 if ((!voice_info || voice_info->rejected) && voice_channel_) { 1467 mediastream_signaling_->OnAudioChannelClose(); 1468 SignalVoiceChannelDestroyed(); 1469 const std::string content_name = voice_channel_->content_name(); 1470 channel_manager_->DestroyVoiceChannel(voice_channel_.release()); 1471 DestroyTransportProxy(content_name); 1472 } 1473 1474 const cricket::ContentInfo* data_info = 1475 cricket::GetFirstDataContent(desc); 1476 if ((!data_info || data_info->rejected) && data_channel_) { 1477 mediastream_signaling_->OnDataChannelClose(); 1478 SignalDataChannelDestroyed(); 1479 const std::string content_name = data_channel_->content_name(); 1480 channel_manager_->DestroyDataChannel(data_channel_.release()); 1481 DestroyTransportProxy(content_name); 1482 } 1483 } 1484 1485 // TODO(mallinath) - Add a correct error code if the channels are not creatued 1486 // due to BUNDLE is enabled but rtcp-mux is disabled. 1487 bool WebRtcSession::CreateChannels(const SessionDescription* desc) { 1488 // Disabling the BUNDLE flag in PortAllocator if offer disabled it. 1489 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE); 1490 if (state() == STATE_INIT && !bundle_enabled) { 1491 port_allocator()->set_flags(port_allocator()->flags() & 1492 ~cricket::PORTALLOCATOR_ENABLE_BUNDLE); 1493 } 1494 1495 // Creating the media channels and transport proxies. 1496 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc); 1497 if (voice && !voice->rejected && !voice_channel_) { 1498 if (!CreateVoiceChannel(voice)) { 1499 LOG(LS_ERROR) << "Failed to create voice channel."; 1500 return false; 1501 } 1502 } 1503 1504 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc); 1505 if (video && !video->rejected && !video_channel_) { 1506 if (!CreateVideoChannel(video)) { 1507 LOG(LS_ERROR) << "Failed to create video channel."; 1508 return false; 1509 } 1510 } 1511 1512 const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc); 1513 if (data_channel_type_ != cricket::DCT_NONE && 1514 data && !data->rejected && !data_channel_.get()) { 1515 if (!CreateDataChannel(data)) { 1516 LOG(LS_ERROR) << "Failed to create data channel."; 1517 return false; 1518 } 1519 } 1520 1521 return true; 1522 } 1523 1524 bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) { 1525 voice_channel_.reset(channel_manager_->CreateVoiceChannel( 1526 this, content->name, true)); 1527 if (!voice_channel_.get()) 1528 return false; 1529 1530 voice_channel_->SetChannelOptions(audio_options_); 1531 return true; 1532 } 1533 1534 bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) { 1535 video_channel_.reset(channel_manager_->CreateVideoChannel( 1536 this, content->name, true, voice_channel_.get())); 1537 if (!video_channel_.get()) 1538 return false; 1539 1540 video_channel_->SetChannelOptions(video_options_); 1541 return true; 1542 } 1543 1544 bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) { 1545 bool sctp = (data_channel_type_ == cricket::DCT_SCTP); 1546 data_channel_.reset(channel_manager_->CreateDataChannel( 1547 this, content->name, !sctp, data_channel_type_)); 1548 if (!data_channel_.get()) { 1549 return false; 1550 } 1551 if (sctp) { 1552 mediastream_signaling_->OnDataTransportCreatedForSctp(); 1553 data_channel_->SignalDataReceived.connect( 1554 this, &WebRtcSession::OnDataChannelMessageReceived); 1555 data_channel_->SignalStreamClosedRemotely.connect( 1556 mediastream_signaling_, 1557 &MediaStreamSignaling::OnRemoteSctpDataChannelClosed); 1558 } 1559 return true; 1560 } 1561 1562 void WebRtcSession::CopySavedCandidates( 1563 SessionDescriptionInterface* dest_desc) { 1564 if (!dest_desc) { 1565 ASSERT(false); 1566 return; 1567 } 1568 for (size_t i = 0; i < saved_candidates_.size(); ++i) { 1569 dest_desc->AddCandidate(saved_candidates_[i]); 1570 delete saved_candidates_[i]; 1571 } 1572 saved_candidates_.clear(); 1573 } 1574 1575 void WebRtcSession::OnDataChannelMessageReceived( 1576 cricket::DataChannel* channel, 1577 const cricket::ReceiveDataParams& params, 1578 const rtc::Buffer& payload) { 1579 ASSERT(data_channel_type_ == cricket::DCT_SCTP); 1580 if (params.type == cricket::DMT_CONTROL && 1581 mediastream_signaling_->IsSctpSidAvailable(params.ssrc)) { 1582 // Received CONTROL on unused sid, process as an OPEN message. 1583 mediastream_signaling_->AddDataChannelFromOpenMessage(params, payload); 1584 } 1585 // otherwise ignore the message. 1586 } 1587 1588 // Returns false if bundle is enabled and rtcp_mux is disabled. 1589 bool WebRtcSession::ValidateBundleSettings(const SessionDescription* desc) { 1590 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE); 1591 if (!bundle_enabled) 1592 return true; 1593 1594 const cricket::ContentGroup* bundle_group = 1595 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE); 1596 ASSERT(bundle_group != NULL); 1597 1598 const cricket::ContentInfos& contents = desc->contents(); 1599 for (cricket::ContentInfos::const_iterator citer = contents.begin(); 1600 citer != contents.end(); ++citer) { 1601 const cricket::ContentInfo* content = (&*citer); 1602 ASSERT(content != NULL); 1603 if (bundle_group->HasContentName(content->name) && 1604 !content->rejected && content->type == cricket::NS_JINGLE_RTP) { 1605 if (!HasRtcpMuxEnabled(content)) 1606 return false; 1607 } 1608 } 1609 // RTCP-MUX is enabled in all the contents. 1610 return true; 1611 } 1612 1613 bool WebRtcSession::HasRtcpMuxEnabled( 1614 const cricket::ContentInfo* content) { 1615 const cricket::MediaContentDescription* description = 1616 static_cast<cricket::MediaContentDescription*>(content->description); 1617 return description->rtcp_mux(); 1618 } 1619 1620 bool WebRtcSession::ValidateSessionDescription( 1621 const SessionDescriptionInterface* sdesc, 1622 cricket::ContentSource source, std::string* err_desc) { 1623 std::string type; 1624 if (error() != cricket::BaseSession::ERROR_NONE) { 1625 return BadSdp(source, type, GetSessionErrorMsg(), err_desc); 1626 } 1627 1628 if (!sdesc || !sdesc->description()) { 1629 return BadSdp(source, type, kInvalidSdp, err_desc); 1630 } 1631 1632 type = sdesc->type(); 1633 Action action = GetAction(sdesc->type()); 1634 if (source == cricket::CS_LOCAL) { 1635 if (!ExpectSetLocalDescription(action)) 1636 return BadLocalSdp(type, BadStateErrMsg(state()), err_desc); 1637 } else { 1638 if (!ExpectSetRemoteDescription(action)) 1639 return BadRemoteSdp(type, BadStateErrMsg(state()), err_desc); 1640 } 1641 1642 // Verify crypto settings. 1643 std::string crypto_error; 1644 if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED || 1645 dtls_enabled_) && 1646 !VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) { 1647 return BadSdp(source, type, crypto_error, err_desc); 1648 } 1649 1650 // Verify ice-ufrag and ice-pwd. 1651 if (!VerifyIceUfragPwdPresent(sdesc->description())) { 1652 return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc); 1653 } 1654 1655 if (!ValidateBundleSettings(sdesc->description())) { 1656 return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc); 1657 } 1658 1659 // Verify m-lines in Answer when compared against Offer. 1660 if (action == kAnswer) { 1661 const cricket::SessionDescription* offer_desc = 1662 (source == cricket::CS_LOCAL) ? remote_description()->description() : 1663 local_description()->description(); 1664 if (!VerifyMediaDescriptions(sdesc->description(), offer_desc)) { 1665 return BadAnswerSdp(source, kMlineMismatch, err_desc); 1666 } 1667 } 1668 1669 return true; 1670 } 1671 1672 bool WebRtcSession::ExpectSetLocalDescription(Action action) { 1673 return ((action == kOffer && state() == STATE_INIT) || 1674 // update local offer 1675 (action == kOffer && state() == STATE_SENTINITIATE) || 1676 // update the current ongoing session. 1677 (action == kOffer && state() == STATE_RECEIVEDACCEPT) || 1678 (action == kOffer && state() == STATE_SENTACCEPT) || 1679 (action == kOffer && state() == STATE_INPROGRESS) || 1680 // accept remote offer 1681 (action == kAnswer && state() == STATE_RECEIVEDINITIATE) || 1682 (action == kAnswer && state() == STATE_SENTPRACCEPT) || 1683 (action == kPrAnswer && state() == STATE_RECEIVEDINITIATE) || 1684 (action == kPrAnswer && state() == STATE_SENTPRACCEPT)); 1685 } 1686 1687 bool WebRtcSession::ExpectSetRemoteDescription(Action action) { 1688 return ((action == kOffer && state() == STATE_INIT) || 1689 // update remote offer 1690 (action == kOffer && state() == STATE_RECEIVEDINITIATE) || 1691 // update the current ongoing session 1692 (action == kOffer && state() == STATE_RECEIVEDACCEPT) || 1693 (action == kOffer && state() == STATE_SENTACCEPT) || 1694 (action == kOffer && state() == STATE_INPROGRESS) || 1695 // accept local offer 1696 (action == kAnswer && state() == STATE_SENTINITIATE) || 1697 (action == kAnswer && state() == STATE_RECEIVEDPRACCEPT) || 1698 (action == kPrAnswer && state() == STATE_SENTINITIATE) || 1699 (action == kPrAnswer && state() == STATE_RECEIVEDPRACCEPT)); 1700 } 1701 1702 std::string WebRtcSession::GetSessionErrorMsg() { 1703 std::ostringstream desc; 1704 desc << kSessionError << GetErrorCodeString(error()) << ". "; 1705 desc << kSessionErrorDesc << error_desc() << "."; 1706 return desc.str(); 1707 } 1708 1709 // We need to check the local/remote description for the Transport instead of 1710 // the session, because a new Transport added during renegotiation may have 1711 // them unset while the session has them set from the previous negotiation. 1712 // Not doing so may trigger the auto generation of transport description and 1713 // mess up DTLS identity information, ICE credential, etc. 1714 bool WebRtcSession::ReadyToUseRemoteCandidate( 1715 const IceCandidateInterface* candidate, 1716 const SessionDescriptionInterface* remote_desc, 1717 bool* valid) { 1718 *valid = true;; 1719 cricket::TransportProxy* transport_proxy = NULL; 1720 1721 const SessionDescriptionInterface* current_remote_desc = 1722 remote_desc ? remote_desc : remote_description(); 1723 1724 if (!current_remote_desc) 1725 return false; 1726 1727 size_t mediacontent_index = 1728 static_cast<size_t>(candidate->sdp_mline_index()); 1729 size_t remote_content_size = 1730 current_remote_desc->description()->contents().size(); 1731 if (mediacontent_index >= remote_content_size) { 1732 LOG(LS_ERROR) 1733 << "ReadyToUseRemoteCandidate: Invalid candidate media index."; 1734 1735 *valid = false; 1736 return false; 1737 } 1738 1739 cricket::ContentInfo content = 1740 current_remote_desc->description()->contents()[mediacontent_index]; 1741 transport_proxy = GetTransportProxy(content.name); 1742 1743 return transport_proxy && transport_proxy->local_description_set() && 1744 transport_proxy->remote_description_set(); 1745 } 1746 1747 } // namespace webrtc 1748