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