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