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