Home | History | Annotate | Download | only in webrtc
      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