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