/*
 * libjingle
 * Copyright 2004 Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "talk/session/media/mediasession.h"

#include <functional>
#include <map>
#include <set>
#include <utility>

#include "talk/base/helpers.h"
#include "talk/base/logging.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/stringutils.h"
#include "talk/media/base/constants.h"
#include "talk/media/base/cryptoparams.h"
#include "talk/p2p/base/constants.h"
#include "talk/session/media/channelmanager.h"
#include "talk/session/media/srtpfilter.h"
#include "talk/xmpp/constants.h"

#ifdef HAVE_SCTP
#include "talk/media/sctp/sctpdataengine.h"
#else
static const uint32 kMaxSctpSid = 1023;
#endif

namespace {
const char kInline[] = "inline:";
}

namespace cricket {

using talk_base::scoped_ptr;

// RTP Profile names
// http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
// RFC4585
const char kMediaProtocolAvpf[] = "RTP/AVPF";
// RFC5124
const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";

// This should be replaced by "UDP/TLS/RTP/SAVPF", but we need to support it for
// now to be compatible with previous Chrome versions.
const char kMediaProtocolSavpf[] = "RTP/SAVPF";

const char kMediaProtocolRtpPrefix[] = "RTP/";

const char kMediaProtocolSctp[] = "SCTP";
const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";

static bool IsMediaContentOfType(const ContentInfo* content,
                                 MediaType media_type) {
  if (!IsMediaContent(content)) {
    return false;
  }

  const MediaContentDescription* mdesc =
      static_cast<const MediaContentDescription*>(content->description);
  return mdesc && mdesc->type() == media_type;
}

static bool CreateCryptoParams(int tag, const std::string& cipher,
                               CryptoParams *out) {
  std::string key;
  key.reserve(SRTP_MASTER_KEY_BASE64_LEN);

  if (!talk_base::CreateRandomString(SRTP_MASTER_KEY_BASE64_LEN, &key)) {
    return false;
  }
  out->tag = tag;
  out->cipher_suite = cipher;
  out->key_params = kInline;
  out->key_params += key;
  return true;
}

#ifdef HAVE_SRTP
static bool AddCryptoParams(const std::string& cipher_suite,
                            CryptoParamsVec *out) {
  int size = static_cast<int>(out->size());

  out->resize(size + 1);
  return CreateCryptoParams(size, cipher_suite, &out->at(size));
}

void AddMediaCryptos(const CryptoParamsVec& cryptos,
                     MediaContentDescription* media) {
  for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
       crypto != cryptos.end(); ++crypto) {
    media->AddCrypto(*crypto);
  }
}

bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
                        MediaContentDescription* media) {
  CryptoParamsVec cryptos;
  for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
       it != crypto_suites.end(); ++it) {
    if (!AddCryptoParams(*it, &cryptos)) {
      return false;
    }
  }
  AddMediaCryptos(cryptos, media);
  return true;
}
#endif

const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
  if (!media) {
    return NULL;
  }
  return &media->cryptos();
}

bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
                        const CryptoParams& crypto,
                        CryptoParams* out) {
  for (CryptoParamsVec::const_iterator it = cryptos.begin();
       it != cryptos.end(); ++it) {
    if (crypto.Matches(*it)) {
      *out = *it;
      return true;
    }
  }
  return false;
}

// For audio, HMAC 32 is prefered because of the low overhead.
void GetSupportedAudioCryptoSuites(
    std::vector<std::string>* crypto_suites) {
#ifdef HAVE_SRTP
  crypto_suites->push_back(CS_AES_CM_128_HMAC_SHA1_32);
  crypto_suites->push_back(CS_AES_CM_128_HMAC_SHA1_80);
#endif
}

void GetSupportedVideoCryptoSuites(
    std::vector<std::string>* crypto_suites) {
  GetSupportedDefaultCryptoSuites(crypto_suites);
}

void GetSupportedDataCryptoSuites(
    std::vector<std::string>* crypto_suites) {
  GetSupportedDefaultCryptoSuites(crypto_suites);
}

void GetSupportedDefaultCryptoSuites(
    std::vector<std::string>* crypto_suites) {
#ifdef HAVE_SRTP
  crypto_suites->push_back(CS_AES_CM_128_HMAC_SHA1_80);
#endif
}

// For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is
// tolerated unless bundle is enabled because it is low overhead. Pick the
// crypto in the list that is supported.
static bool SelectCrypto(const MediaContentDescription* offer,
                         bool bundle,
                         CryptoParams *crypto) {
  bool audio = offer->type() == MEDIA_TYPE_AUDIO;
  const CryptoParamsVec& cryptos = offer->cryptos();

  for (CryptoParamsVec::const_iterator i = cryptos.begin();
       i != cryptos.end(); ++i) {
    if (CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
        (CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio && !bundle)) {
      return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
    }
  }
  return false;
}

static const StreamParams* FindFirstStreamParamsByCname(
    const StreamParamsVec& params_vec,
    const std::string& cname) {
  for (StreamParamsVec::const_iterator it = params_vec.begin();
       it != params_vec.end(); ++it) {
    if (cname == it->cname)
      return &*it;
  }
  return NULL;
}

// Generates a new CNAME or the CNAME of an already existing StreamParams
// if a StreamParams exist for another Stream in streams with sync_label
// sync_label.
static bool GenerateCname(const StreamParamsVec& params_vec,
                          const MediaSessionOptions::Streams& streams,
                          const std::string& synch_label,
                          std::string* cname) {
  ASSERT(cname != NULL);
  if (!cname)
    return false;

  // Check if a CNAME exist for any of the other synched streams.
  for (MediaSessionOptions::Streams::const_iterator stream_it = streams.begin();
       stream_it != streams.end() ; ++stream_it) {
    if (synch_label != stream_it->sync_label)
      continue;

    StreamParams param;
    // groupid is empty for StreamParams generated using
    // MediaSessionDescriptionFactory.
    if (GetStreamByIds(params_vec, "", stream_it->id,
                       &param)) {
      *cname = param.cname;
      return true;
    }
  }
  // No other stream seems to exist that we should sync with.
  // Generate a random string for the RTCP CNAME, as stated in RFC 6222.
  // This string is only used for synchronization, and therefore is opaque.
  do {
    if (!talk_base::CreateRandomString(16, cname)) {
      ASSERT(false);
      return false;
    }
  } while (FindFirstStreamParamsByCname(params_vec, *cname));

  return true;
}

// Generate random SSRC values that are not already present in |params_vec|.
// The generated values are added to |ssrcs|.
// |num_ssrcs| is the number of the SSRC will be generated.
static void GenerateSsrcs(const StreamParamsVec& params_vec,
                          int num_ssrcs,
                          std::vector<uint32>* ssrcs) {
  for (int i = 0; i < num_ssrcs; i++) {
    uint32 candidate;
    do {
      candidate = talk_base::CreateRandomNonZeroId();
    } while (GetStreamBySsrc(params_vec, candidate, NULL) ||
             std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
    ssrcs->push_back(candidate);
  }
}

// Returns false if we exhaust the range of SIDs.
static bool GenerateSctpSid(const StreamParamsVec& params_vec,
                            uint32* sid) {
  if (params_vec.size() > kMaxSctpSid) {
    LOG(LS_WARNING) <<
        "Could not generate an SCTP SID: too many SCTP streams.";
    return false;
  }
  while (true) {
    uint32 candidate = talk_base::CreateRandomNonZeroId() % kMaxSctpSid;
    if (!GetStreamBySsrc(params_vec, candidate, NULL)) {
      *sid = candidate;
      return true;
    }
  }
}

static bool GenerateSctpSids(const StreamParamsVec& params_vec,
                             std::vector<uint32>* sids) {
  uint32 sid;
  if (!GenerateSctpSid(params_vec, &sid)) {
    LOG(LS_WARNING) << "Could not generated an SCTP SID.";
    return false;
  }
  sids->push_back(sid);
  return true;
}

// Finds all StreamParams of all media types and attach them to stream_params.
static void GetCurrentStreamParams(const SessionDescription* sdesc,
                                   StreamParamsVec* stream_params) {
  if (!sdesc)
    return;

  const ContentInfos& contents = sdesc->contents();
  for (ContentInfos::const_iterator content = contents.begin();
       content != contents.end(); ++content) {
    if (!IsMediaContent(&*content)) {
      continue;
    }
    const MediaContentDescription* media =
        static_cast<const MediaContentDescription*>(
            content->description);
    const StreamParamsVec& streams = media->streams();
    for (StreamParamsVec::const_iterator it = streams.begin();
         it != streams.end(); ++it) {
      stream_params->push_back(*it);
    }
  }
}

// Filters the data codecs for the data channel type.
void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
  // Filter RTP codec for SCTP and vice versa.
  int codec_id = sctp ? kGoogleRtpDataCodecId : kGoogleSctpDataCodecId;
  for (std::vector<DataCodec>::iterator iter = codecs->begin();
       iter != codecs->end();) {
    if (iter->id == codec_id) {
      iter = codecs->erase(iter);
    } else {
      ++iter;
    }
  }
}

template <typename IdStruct>
class UsedIds {
 public:
  UsedIds(int min_allowed_id, int max_allowed_id)
      : min_allowed_id_(min_allowed_id),
        max_allowed_id_(max_allowed_id),
        next_id_(max_allowed_id) {
  }

  // Loops through all Id in |ids| and changes its id if it is
  // already in use by another IdStruct. Call this methods with all Id
  // in a session description to make sure no duplicate ids exists.
  // Note that typename Id must be a type of IdStruct.
  template <typename Id>
  void FindAndSetIdUsed(std::vector<Id>* ids) {
    for (typename std::vector<Id>::iterator it = ids->begin();
         it != ids->end(); ++it) {
      FindAndSetIdUsed(&*it);
    }
  }

  // Finds and sets an unused id if the |idstruct| id is already in use.
  void FindAndSetIdUsed(IdStruct* idstruct) {
    const int original_id = idstruct->id;
    int new_id = idstruct->id;

    if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
      // If the original id is not in range - this is an id that can't be
      // dynamically changed.
      return;
    }

    if (IsIdUsed(original_id)) {
      new_id = FindUnusedId();
      LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
          << " to " << new_id;
      idstruct->id = new_id;
    }
    SetIdUsed(new_id);
  }

 private:
  // Returns the first unused id in reverse order.
  // This hopefully reduce the risk of more collisions. We want to change the
  // default ids as little as possible.
  int FindUnusedId() {
    while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
      --next_id_;
    }
    ASSERT(next_id_ >= min_allowed_id_);
    return next_id_;
  }

  bool IsIdUsed(int new_id) {
    return id_set_.find(new_id) != id_set_.end();
  }

  void SetIdUsed(int new_id) {
    id_set_.insert(new_id);
  }

  const int min_allowed_id_;
  const int max_allowed_id_;
  int next_id_;
  std::set<int> id_set_;
};

// Helper class used for finding duplicate RTP payload types among audio, video
// and data codecs. When bundle is used the payload types may not collide.
class UsedPayloadTypes : public UsedIds<Codec> {
 public:
  UsedPayloadTypes()
      : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
  }


 private:
  static const int kDynamicPayloadTypeMin = 96;
  static const int kDynamicPayloadTypeMax = 127;
};

// Helper class used for finding duplicate RTP Header extension ids among
// audio and video extensions.
class UsedRtpHeaderExtensionIds : public UsedIds<RtpHeaderExtension> {
 public:
  UsedRtpHeaderExtensionIds()
      : UsedIds<RtpHeaderExtension>(kLocalIdMin, kLocalIdMax) {
  }

 private:
  // Min and Max local identifier for one-byte header extensions, per RFC5285.
  static const int kLocalIdMin = 1;
  static const int kLocalIdMax = 14;
};

static bool IsSctp(const MediaContentDescription* desc) {
  return ((desc->protocol() == kMediaProtocolSctp) ||
          (desc->protocol() == kMediaProtocolDtlsSctp));
}

// Adds a StreamParams for each Stream in Streams with media type
// media_type to content_description.
// |current_params| - All currently known StreamParams of any media type.
template <class C>
static bool AddStreamParams(
    MediaType media_type,
    const MediaSessionOptions::Streams& streams,
    StreamParamsVec* current_streams,
    MediaContentDescriptionImpl<C>* content_description,
    const bool add_legacy_stream) {
  const bool include_rtx_stream =
    ContainsRtxCodec(content_description->codecs());

  if (streams.empty() && add_legacy_stream) {
    // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
    std::vector<uint32> ssrcs;
    if (IsSctp(content_description)) {
      GenerateSctpSids(*current_streams, &ssrcs);
    } else {
      int num_ssrcs = include_rtx_stream ? 2 : 1;
      GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
    }
    if (include_rtx_stream) {
      content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
      content_description->set_multistream(true);
    } else {
      content_description->AddLegacyStream(ssrcs[0]);
    }
    return true;
  }

  MediaSessionOptions::Streams::const_iterator stream_it;
  for (stream_it = streams.begin();
       stream_it != streams.end(); ++stream_it) {
    if (stream_it->type != media_type)
      continue;  // Wrong media type.

    StreamParams param;
    // groupid is empty for StreamParams generated using
    // MediaSessionDescriptionFactory.
    if (!GetStreamByIds(*current_streams, "", stream_it->id,
                        &param)) {
      // This is a new stream.
      // Get a CNAME. Either new or same as one of the other synched streams.
      std::string cname;
      if (!GenerateCname(*current_streams, streams, stream_it->sync_label,
                         &cname)) {
        return false;
      }

      std::vector<uint32> ssrcs;
      if (IsSctp(content_description)) {
        GenerateSctpSids(*current_streams, &ssrcs);
      } else {
        GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
      }
      StreamParams stream_param;
      stream_param.id = stream_it->id;
      // Add the generated ssrc.
      for (size_t i = 0; i < ssrcs.size(); ++i) {
        stream_param.ssrcs.push_back(ssrcs[i]);
      }
      if (stream_it->num_sim_layers > 1) {
        SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
        stream_param.ssrc_groups.push_back(group);
      }
      // Generate an extra ssrc for include_rtx_stream case.
      if (include_rtx_stream) {
        std::vector<uint32> rtx_ssrc;
        GenerateSsrcs(*current_streams, 1, &rtx_ssrc);
        stream_param.AddFidSsrc(ssrcs[0], rtx_ssrc[0]);
        content_description->set_multistream(true);
      }
      stream_param.cname = cname;
      stream_param.sync_label = stream_it->sync_label;
      content_description->AddStream(stream_param);

      // Store the new StreamParams in current_streams.
      // This is necessary so that we can use the CNAME for other media types.
      current_streams->push_back(stream_param);
    } else {
      content_description->AddStream(param);
    }
  }
  return true;
}

// Updates the transport infos of the |sdesc| according to the given
// |bundle_group|. The transport infos of the content names within the
// |bundle_group| should be updated to use the ufrag and pwd of the first
// content within the |bundle_group|.
static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
                                         SessionDescription* sdesc) {
  // The bundle should not be empty.
  if (!sdesc || !bundle_group.FirstContentName()) {
    return false;
  }

  // We should definitely have a transport for the first content.
  std::string selected_content_name = *bundle_group.FirstContentName();
  const TransportInfo* selected_transport_info =
      sdesc->GetTransportInfoByName(selected_content_name);
  if (!selected_transport_info) {
    return false;
  }

  // Set the other contents to use the same ICE credentials.
  const std::string selected_ufrag =
      selected_transport_info->description.ice_ufrag;
  const std::string selected_pwd =
      selected_transport_info->description.ice_pwd;
  for (TransportInfos::iterator it =
           sdesc->transport_infos().begin();
       it != sdesc->transport_infos().end(); ++it) {
    if (bundle_group.HasContentName(it->content_name) &&
        it->content_name != selected_content_name) {
      it->description.ice_ufrag = selected_ufrag;
      it->description.ice_pwd = selected_pwd;
    }
  }
  return true;
}

// Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
// sets it to |cryptos|.
static bool GetCryptosByName(const SessionDescription* sdesc,
                             const std::string& content_name,
                             CryptoParamsVec* cryptos) {
  if (!sdesc || !cryptos) {
    return false;
  }

  const ContentInfo* content = sdesc->GetContentByName(content_name);
  if (!IsMediaContent(content) || !content->description) {
    return false;
  }

  const MediaContentDescription* media_desc =
      static_cast<const MediaContentDescription*>(content->description);
  *cryptos = media_desc->cryptos();
  return true;
}

// Predicate function used by the remove_if.
// Returns true if the |crypto|'s cipher_suite is not found in |filter|.
static bool CryptoNotFound(const CryptoParams crypto,
                           const CryptoParamsVec* filter) {
  if (filter == NULL) {
    return true;
  }
  for (CryptoParamsVec::const_iterator it = filter->begin();
       it != filter->end(); ++it) {
    if (it->cipher_suite == crypto.cipher_suite) {
      return false;
    }
  }
  return true;
}

// Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
// which are not available in |filter|.
static void PruneCryptos(const CryptoParamsVec& filter,
                         CryptoParamsVec* target_cryptos) {
  if (!target_cryptos) {
    return;
  }
  target_cryptos->erase(std::remove_if(target_cryptos->begin(),
                                       target_cryptos->end(),
                                       bind2nd(ptr_fun(CryptoNotFound),
                                               &filter)),
                        target_cryptos->end());
}

static bool IsRtpContent(SessionDescription* sdesc,
                         const std::string& content_name) {
  bool is_rtp = false;
  ContentInfo* content = sdesc->GetContentByName(content_name);
  if (IsMediaContent(content)) {
    MediaContentDescription* media_desc =
        static_cast<MediaContentDescription*>(content->description);
    if (!media_desc) {
      return false;
    }
    is_rtp = media_desc->protocol().empty() ||
             talk_base::starts_with(media_desc->protocol().data(),
                                    kMediaProtocolRtpPrefix);
  }
  return is_rtp;
}

// Updates the crypto parameters of the |sdesc| according to the given
// |bundle_group|. The crypto parameters of all the contents within the
// |bundle_group| should be updated to use the common subset of the
// available cryptos.
static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
                                        SessionDescription* sdesc) {
  // The bundle should not be empty.
  if (!sdesc || !bundle_group.FirstContentName()) {
    return false;
  }

  bool common_cryptos_needed = false;
  // Get the common cryptos.
  const ContentNames& content_names = bundle_group.content_names();
  CryptoParamsVec common_cryptos;
  for (ContentNames::const_iterator it = content_names.begin();
       it != content_names.end(); ++it) {
    if (!IsRtpContent(sdesc, *it)) {
      continue;
    }
    // The common cryptos are needed if any of the content does not have DTLS
    // enabled.
    if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
      common_cryptos_needed = true;
    }
    if (it == content_names.begin()) {
      // Initial the common_cryptos with the first content in the bundle group.
      if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
        return false;
      }
      if (common_cryptos.empty()) {
        // If there's no crypto params, we should just return.
        return true;
      }
    } else {
      CryptoParamsVec cryptos;
      if (!GetCryptosByName(sdesc, *it, &cryptos)) {
        return false;
      }
      PruneCryptos(cryptos, &common_cryptos);
    }
  }

  if (common_cryptos.empty() && common_cryptos_needed) {
    return false;
  }

  // Update to use the common cryptos.
  for (ContentNames::const_iterator it = content_names.begin();
       it != content_names.end(); ++it) {
    if (!IsRtpContent(sdesc, *it)) {
      continue;
    }
    ContentInfo* content = sdesc->GetContentByName(*it);
    if (IsMediaContent(content)) {
      MediaContentDescription* media_desc =
          static_cast<MediaContentDescription*>(content->description);
      if (!media_desc) {
        return false;
      }
      media_desc->set_cryptos(common_cryptos);
    }
  }
  return true;
}

template <class C>
static bool ContainsRtxCodec(const std::vector<C>& codecs) {
  typename std::vector<C>::const_iterator it;
  for (it = codecs.begin(); it != codecs.end(); ++it) {
    if (IsRtxCodec(*it)) {
      return true;
    }
  }
  return false;
}

template <class C>
static bool IsRtxCodec(const C& codec) {
  return stricmp(codec.name.c_str(), kRtxCodecName) == 0;
}

// Create a media content to be offered in a session-initiate,
// according to the given options.rtcp_mux, options.is_muc,
// options.streams, codecs, secure_transport, crypto, and streams.  If we don't
// currently have crypto (in current_cryptos) and it is enabled (in
// secure_policy), crypto is created (according to crypto_suites).  If
// add_legacy_stream is true, and current_streams is empty, a legacy
// stream is created.  The created content is added to the offer.
template <class C>
static bool CreateMediaContentOffer(
    const MediaSessionOptions& options,
    const std::vector<C>& codecs,
    const SecurePolicy& secure_policy,
    const CryptoParamsVec* current_cryptos,
    const std::vector<std::string>& crypto_suites,
    const RtpHeaderExtensions& rtp_extensions,
    bool add_legacy_stream,
    StreamParamsVec* current_streams,
    MediaContentDescriptionImpl<C>* offer) {
  offer->AddCodecs(codecs);
  offer->SortCodecs();

  if (secure_policy == SEC_REQUIRED) {
    offer->set_crypto_required(CT_SDES);
  }
  offer->set_rtcp_mux(options.rtcp_mux_enabled);
  offer->set_multistream(options.is_muc);
  offer->set_rtp_header_extensions(rtp_extensions);

  if (!AddStreamParams(
          offer->type(), options.streams, current_streams,
          offer, add_legacy_stream)) {
    return false;
  }

#ifdef HAVE_SRTP
  if (secure_policy != SEC_DISABLED) {
    if (current_cryptos) {
      AddMediaCryptos(*current_cryptos, offer);
    }
    if (offer->cryptos().empty()) {
      if (!CreateMediaCryptos(crypto_suites, offer)) {
        return false;
      }
    }
  }
#endif

  if (offer->crypto_required() == CT_SDES && offer->cryptos().empty()) {
    return false;
  }
  return true;
}

template <class C>
static void NegotiateCodecs(const std::vector<C>& local_codecs,
                            const std::vector<C>& offered_codecs,
                            std::vector<C>* negotiated_codecs) {
  typename std::vector<C>::const_iterator ours;
  for (ours = local_codecs.begin();
       ours != local_codecs.end(); ++ours) {
    typename std::vector<C>::const_iterator theirs;
    for (theirs = offered_codecs.begin();
         theirs != offered_codecs.end(); ++theirs) {
      if (ours->Matches(*theirs)) {
        C negotiated = *ours;
        negotiated.IntersectFeedbackParams(*theirs);
        if (IsRtxCodec(negotiated)) {
          // Only negotiate RTX if kCodecParamAssociatedPayloadType has been
          // set.
          std::string apt_value;
          if (!theirs->GetParam(kCodecParamAssociatedPayloadType, &apt_value)) {
            LOG(LS_WARNING) << "RTX missing associated payload type.";
            continue;
          }
          negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_value);
        }
        negotiated.id = theirs->id;
        negotiated_codecs->push_back(negotiated);
      }
    }
  }
}

template <class C>
static bool FindMatchingCodec(const std::vector<C>& codecs,
                              const C& codec_to_match,
                              C* found_codec) {
  for (typename std::vector<C>::const_iterator it = codecs.begin();
       it  != codecs.end(); ++it) {
    if (it->Matches(codec_to_match)) {
      if (found_codec != NULL) {
        *found_codec= *it;
      }
      return true;
    }
  }
  return false;
}

// Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
// already exist in |offered_codecs| and ensure the payload types don't
// collide.
template <class C>
static void FindCodecsToOffer(
    const std::vector<C>& reference_codecs,
    std::vector<C>* offered_codecs,
    UsedPayloadTypes* used_pltypes) {

  typedef std::map<int, C> RtxCodecReferences;
  RtxCodecReferences new_rtx_codecs;

  // Find all new RTX codecs.
  for (typename std::vector<C>::const_iterator it = reference_codecs.begin();
       it != reference_codecs.end(); ++it) {
    if (!FindMatchingCodec<C>(*offered_codecs, *it, NULL) && IsRtxCodec(*it)) {
      C rtx_codec = *it;
      int referenced_pl_type =
          talk_base::FromString<int>(0,
              rtx_codec.params[kCodecParamAssociatedPayloadType]);
      new_rtx_codecs.insert(std::pair<int, C>(referenced_pl_type,
                                              rtx_codec));
    }
  }

  // Add all new codecs that are not RTX codecs.
  for (typename std::vector<C>::const_iterator it = reference_codecs.begin();
       it != reference_codecs.end(); ++it) {
    if (!FindMatchingCodec<C>(*offered_codecs, *it, NULL) && !IsRtxCodec(*it)) {
      C codec = *it;
      int original_payload_id = codec.id;
      used_pltypes->FindAndSetIdUsed(&codec);
      offered_codecs->push_back(codec);

      // If this codec is referenced by a new RTX codec, update the reference
      // in the RTX codec with the new payload type.
      typename RtxCodecReferences::iterator rtx_it =
          new_rtx_codecs.find(original_payload_id);
      if (rtx_it != new_rtx_codecs.end()) {
        C& rtx_codec = rtx_it->second;
        rtx_codec.params[kCodecParamAssociatedPayloadType] =
            talk_base::ToString(codec.id);
      }
    }
  }

  // Add all new RTX codecs.
  for (typename RtxCodecReferences::iterator it = new_rtx_codecs.begin();
       it != new_rtx_codecs.end(); ++it) {
    C& rtx_codec = it->second;
    used_pltypes->FindAndSetIdUsed(&rtx_codec);
    offered_codecs->push_back(rtx_codec);
  }
}


static bool FindByUri(const RtpHeaderExtensions& extensions,
                      const RtpHeaderExtension& ext_to_match,
                      RtpHeaderExtension* found_extension) {
  for (RtpHeaderExtensions::const_iterator it = extensions.begin();
       it  != extensions.end(); ++it) {
    // We assume that all URIs are given in a canonical format.
    if (it->uri == ext_to_match.uri) {
      if (found_extension != NULL) {
        *found_extension = *it;
      }
      return true;
    }
  }
  return false;
}

static void FindAndSetRtpHdrExtUsed(
  const RtpHeaderExtensions& reference_extensions,
  RtpHeaderExtensions* offered_extensions,
  const RtpHeaderExtensions& other_extensions,
  UsedRtpHeaderExtensionIds* used_extensions) {
  for (RtpHeaderExtensions::const_iterator it = reference_extensions.begin();
      it != reference_extensions.end(); ++it) {
    if (!FindByUri(*offered_extensions, *it, NULL)) {
      RtpHeaderExtension ext;
      if (!FindByUri(other_extensions, *it, &ext)) {
        ext = *it;
        used_extensions->FindAndSetIdUsed(&ext);
      }
      offered_extensions->push_back(ext);
    }
  }
}

static void NegotiateRtpHeaderExtensions(
    const RtpHeaderExtensions& local_extensions,
    const RtpHeaderExtensions& offered_extensions,
    RtpHeaderExtensions* negotiated_extenstions) {
  RtpHeaderExtensions::const_iterator ours;
  for (ours = local_extensions.begin();
       ours != local_extensions.end(); ++ours) {
    RtpHeaderExtension theirs;
    if (FindByUri(offered_extensions, *ours, &theirs)) {
      // We respond with their RTP header extension id.
      negotiated_extenstions->push_back(theirs);
    }
  }
}

static void StripCNCodecs(AudioCodecs* audio_codecs) {
  AudioCodecs::iterator iter = audio_codecs->begin();
  while (iter != audio_codecs->end()) {
    if (stricmp(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
      iter = audio_codecs->erase(iter);
    } else {
      ++iter;
    }
  }
}

// Create a media content to be answered in a session-accept,
// according to the given options.rtcp_mux, options.streams, codecs,
// crypto, and streams.  If we don't currently have crypto (in
// current_cryptos) and it is enabled (in secure_policy), crypto is
// created (according to crypto_suites).  If add_legacy_stream is
// true, and current_streams is empty, a legacy stream is created.
// The codecs, rtcp_mux, and crypto are all negotiated with the offer
// from the incoming session-initiate.  If the negotiation fails, this
// method returns false.  The created content is added to the offer.
template <class C>
static bool CreateMediaContentAnswer(
    const MediaContentDescriptionImpl<C>* offer,
    const MediaSessionOptions& options,
    const std::vector<C>& local_codecs,
    const SecurePolicy& sdes_policy,
    const CryptoParamsVec* current_cryptos,
    const RtpHeaderExtensions& local_rtp_extenstions,
    StreamParamsVec* current_streams,
    bool add_legacy_stream,
    bool bundle_enabled,
    MediaContentDescriptionImpl<C>* answer) {
  std::vector<C> negotiated_codecs;
  NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
  answer->AddCodecs(negotiated_codecs);
  answer->SortCodecs();
  answer->set_protocol(offer->protocol());
  RtpHeaderExtensions negotiated_rtp_extensions;
  NegotiateRtpHeaderExtensions(local_rtp_extenstions,
                               offer->rtp_header_extensions(),
                               &negotiated_rtp_extensions);
  answer->set_rtp_header_extensions(negotiated_rtp_extensions);

  answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());

  if (sdes_policy != SEC_DISABLED) {
    CryptoParams crypto;
    if (SelectCrypto(offer, bundle_enabled, &crypto)) {
      if (current_cryptos) {
        FindMatchingCrypto(*current_cryptos, crypto, &crypto);
      }
      answer->AddCrypto(crypto);
    }
  }

  if (answer->cryptos().empty() &&
      (offer->crypto_required() == CT_SDES || sdes_policy == SEC_REQUIRED)) {
    return false;
  }

  if (!AddStreamParams(
          answer->type(), options.streams, current_streams,
          answer, add_legacy_stream)) {
    return false;  // Something went seriously wrong.
  }

  // Make sure the answer media content direction is per default set as
  // described in RFC3264 section 6.1.
  switch (offer->direction()) {
    case MD_INACTIVE:
      answer->set_direction(MD_INACTIVE);
      break;
    case MD_SENDONLY:
      answer->set_direction(MD_RECVONLY);
      break;
    case MD_RECVONLY:
      answer->set_direction(MD_SENDONLY);
      break;
    case MD_SENDRECV:
      answer->set_direction(MD_SENDRECV);
      break;
    default:
      break;
  }

  return true;
}

static bool IsMediaProtocolSupported(MediaType type,
                                     const std::string& protocol,
                                     bool secure_transport) {
  // Data channels can have a protocol of SCTP or SCTP/DTLS.
  if (type == MEDIA_TYPE_DATA &&
      ((protocol == kMediaProtocolSctp && !secure_transport)||
       (protocol == kMediaProtocolDtlsSctp && secure_transport))) {
    return true;
  }

  // Since not all applications serialize and deserialize the media protocol,
  // we will have to accept |protocol| to be empty.
  return protocol == kMediaProtocolAvpf || protocol.empty() ||
      protocol == kMediaProtocolSavpf ||
      (protocol == kMediaProtocolDtlsSavpf && secure_transport);
}

static void SetMediaProtocol(bool secure_transport,
                             MediaContentDescription* desc) {
  if (!desc->cryptos().empty() || secure_transport)
    desc->set_protocol(kMediaProtocolSavpf);
  else
    desc->set_protocol(kMediaProtocolAvpf);
}

// Gets the TransportInfo of the given |content_name| from the
// |current_description|. If doesn't exist, returns a new one.
static const TransportDescription* GetTransportDescription(
    const std::string& content_name,
    const SessionDescription* current_description) {
  const TransportDescription* desc = NULL;
  if (current_description) {
    const TransportInfo* info =
        current_description->GetTransportInfoByName(content_name);
    if (info) {
      desc = &info->description;
    }
  }
  return desc;
}

// Gets the current DTLS state from the transport description.
static bool IsDtlsActive(
    const std::string& content_name,
    const SessionDescription* current_description) {
  if (!current_description)
    return false;

  const ContentInfo* content =
      current_description->GetContentByName(content_name);
  if (!content)
    return false;

  const TransportDescription* current_tdesc =
      GetTransportDescription(content_name, current_description);
  if (!current_tdesc)
    return false;

  return current_tdesc->secure();
}

std::string MediaTypeToString(MediaType type) {
  std::string type_str;
  switch (type) {
    case MEDIA_TYPE_AUDIO:
      type_str = "audio";
      break;
    case MEDIA_TYPE_VIDEO:
      type_str = "video";
      break;
    case MEDIA_TYPE_DATA:
      type_str = "data";
      break;
    default:
      ASSERT(false);
      break;
  }
  return type_str;
}

void MediaSessionOptions::AddStream(MediaType type,
                                    const std::string& id,
                                    const std::string& sync_label) {
  AddStreamInternal(type, id, sync_label, 1);
}

void MediaSessionOptions::AddVideoStream(
    const std::string& id,
    const std::string& sync_label,
    int num_sim_layers) {
  AddStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
}

void MediaSessionOptions::AddStreamInternal(
    MediaType type,
    const std::string& id,
    const std::string& sync_label,
    int num_sim_layers) {
  streams.push_back(Stream(type, id, sync_label, num_sim_layers));

  if (type == MEDIA_TYPE_VIDEO)
    has_video = true;
  else if (type == MEDIA_TYPE_AUDIO)
    has_audio = true;
  // If we haven't already set the data_channel_type, and we add a
  // stream, we assume it's an RTP data stream.
  else if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
    data_channel_type = DCT_RTP;
}

void MediaSessionOptions::RemoveStream(MediaType type,
                                       const std::string& id) {
  Streams::iterator stream_it = streams.begin();
  for (; stream_it != streams.end(); ++stream_it) {
    if (stream_it->type == type && stream_it->id == id) {
      streams.erase(stream_it);
      return;
    }
  }
  ASSERT(false);
}

MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
    const TransportDescriptionFactory* transport_desc_factory)
    : secure_(SEC_DISABLED),
      add_legacy_(true),
      transport_desc_factory_(transport_desc_factory) {
}

MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
    ChannelManager* channel_manager,
    const TransportDescriptionFactory* transport_desc_factory)
    : secure_(SEC_DISABLED),
      add_legacy_(true),
      transport_desc_factory_(transport_desc_factory) {
  channel_manager->GetSupportedAudioCodecs(&audio_codecs_);
  channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
  channel_manager->GetSupportedVideoCodecs(&video_codecs_);
  channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
  channel_manager->GetSupportedDataCodecs(&data_codecs_);
}

SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
    const MediaSessionOptions& options,
    const SessionDescription* current_description) const {
  bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);

  scoped_ptr<SessionDescription> offer(new SessionDescription());

  StreamParamsVec current_streams;
  GetCurrentStreamParams(current_description, &current_streams);

  AudioCodecs audio_codecs;
  VideoCodecs video_codecs;
  DataCodecs data_codecs;
  GetCodecsToOffer(current_description, &audio_codecs, &video_codecs,
                   &data_codecs);

  if (!options.vad_enabled) {
    // If application doesn't want CN codecs in offer.
    StripCNCodecs(&audio_codecs);
  }

  RtpHeaderExtensions audio_rtp_extensions;
  RtpHeaderExtensions video_rtp_extensions;
  GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
                       &video_rtp_extensions);

  // Handle m=audio.
  if (options.has_audio) {
    cricket::SecurePolicy sdes_policy =
        IsDtlsActive(CN_AUDIO, current_description) ?
            cricket::SEC_DISABLED : secure();

    scoped_ptr<AudioContentDescription> audio(new AudioContentDescription());
    std::vector<std::string> crypto_suites;
    GetSupportedAudioCryptoSuites(&crypto_suites);
    if (!CreateMediaContentOffer(
            options,
            audio_codecs,
            sdes_policy,
            GetCryptos(GetFirstAudioContentDescription(current_description)),
            crypto_suites,
            audio_rtp_extensions,
            add_legacy_,
            &current_streams,
            audio.get())) {
      return NULL;
    }

    audio->set_lang(lang_);
    SetMediaProtocol(secure_transport, audio.get());
    offer->AddContent(CN_AUDIO, NS_JINGLE_RTP, audio.release());
    if (!AddTransportOffer(CN_AUDIO, options.transport_options,
                           current_description, offer.get())) {
      return NULL;
    }
  }

  // Handle m=video.
  if (options.has_video) {
    cricket::SecurePolicy sdes_policy =
        IsDtlsActive(CN_VIDEO, current_description) ?
            cricket::SEC_DISABLED : secure();

    scoped_ptr<VideoContentDescription> video(new VideoContentDescription());
    std::vector<std::string> crypto_suites;
    GetSupportedVideoCryptoSuites(&crypto_suites);
    if (!CreateMediaContentOffer(
            options,
            video_codecs,
            sdes_policy,
            GetCryptos(GetFirstVideoContentDescription(current_description)),
            crypto_suites,
            video_rtp_extensions,
            add_legacy_,
            &current_streams,
            video.get())) {
      return NULL;
    }

    video->set_bandwidth(options.video_bandwidth);
    SetMediaProtocol(secure_transport, video.get());
    offer->AddContent(CN_VIDEO, NS_JINGLE_RTP, video.release());
    if (!AddTransportOffer(CN_VIDEO, options.transport_options,
                           current_description, offer.get())) {
      return NULL;
    }
  }

  // Handle m=data.
  if (options.has_data()) {
    scoped_ptr<DataContentDescription> data(new DataContentDescription());
    bool is_sctp = (options.data_channel_type == DCT_SCTP);

    FilterDataCodecs(&data_codecs, is_sctp);

    cricket::SecurePolicy sdes_policy =
        IsDtlsActive(CN_DATA, current_description) ?
            cricket::SEC_DISABLED : secure();
    std::vector<std::string> crypto_suites;
    if (is_sctp) {
      // SDES doesn't make sense for SCTP, so we disable it, and we only
      // get SDES crypto suites for RTP-based data channels.
      sdes_policy = cricket::SEC_DISABLED;
      // Unlike SetMediaProtocol below, we need to set the protocol
      // before we call CreateMediaContentOffer.  Otherwise,
      // CreateMediaContentOffer won't know this is SCTP and will
      // generate SSRCs rather than SIDs.
      data->set_protocol(
          secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
    } else {
      GetSupportedDataCryptoSuites(&crypto_suites);
    }

    if (!CreateMediaContentOffer(
            options,
            data_codecs,
            sdes_policy,
            GetCryptos(GetFirstDataContentDescription(current_description)),
            crypto_suites,
            RtpHeaderExtensions(),
            add_legacy_,
            &current_streams,
            data.get())) {
      return NULL;
    }

    if (is_sctp) {
      offer->AddContent(CN_DATA, NS_JINGLE_DRAFT_SCTP, data.release());
    } else {
      data->set_bandwidth(options.data_bandwidth);
      SetMediaProtocol(secure_transport, data.get());
      offer->AddContent(CN_DATA, NS_JINGLE_RTP, data.release());
    }
    if (!AddTransportOffer(CN_DATA, options.transport_options,
                           current_description, offer.get())) {
      return NULL;
    }
  }

  // Bundle the contents together, if we've been asked to do so, and update any
  // parameters that need to be tweaked for BUNDLE.
  if (options.bundle_enabled) {
    ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
    for (ContentInfos::const_iterator content = offer->contents().begin();
       content != offer->contents().end(); ++content) {
      offer_bundle.AddContentName(content->name);
    }
    offer->AddGroup(offer_bundle);
    if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
      LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
      return NULL;
    }
    if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
      LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
      return NULL;
    }
  }

  return offer.release();
}

SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
    const SessionDescription* offer, const MediaSessionOptions& options,
    const SessionDescription* current_description) const {
  // The answer contains the intersection of the codecs in the offer with the
  // codecs we support, ordered by our local preference. As indicated by
  // XEP-0167, we retain the same payload ids from the offer in the answer.
  scoped_ptr<SessionDescription> answer(new SessionDescription());

  StreamParamsVec current_streams;
  GetCurrentStreamParams(current_description, &current_streams);

  bool bundle_enabled =
      offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;

  // Handle m=audio.
  const ContentInfo* audio_content = GetFirstAudioContent(offer);
  if (audio_content) {
    scoped_ptr<TransportDescription> audio_transport(
        CreateTransportAnswer(audio_content->name, offer,
                              options.transport_options,
                              current_description));
    if (!audio_transport) {
      return NULL;
    }

    AudioCodecs audio_codecs = audio_codecs_;
    if (!options.vad_enabled) {
      StripCNCodecs(&audio_codecs);
    }

    scoped_ptr<AudioContentDescription> audio_answer(
        new AudioContentDescription());
    // Do not require or create SDES cryptos if DTLS is used.
    cricket::SecurePolicy sdes_policy =
        audio_transport->secure() ? cricket::SEC_DISABLED : secure();
    if (!CreateMediaContentAnswer(
            static_cast<const AudioContentDescription*>(
                audio_content->description),
            options,
            audio_codecs,
            sdes_policy,
            GetCryptos(GetFirstAudioContentDescription(current_description)),
            audio_rtp_extensions_,
            &current_streams,
            add_legacy_,
            bundle_enabled,
            audio_answer.get())) {
      return NULL;  // Fails the session setup.
    }

    bool rejected = !options.has_audio || audio_content->rejected ||
        !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
                                  audio_answer->protocol(),
                                  audio_transport->secure());
    if (!rejected) {
      AddTransportAnswer(audio_content->name, *(audio_transport.get()),
                         answer.get());
    } else {
      // RFC 3264
      // The answer MUST contain the same number of m-lines as the offer.
      LOG(LS_INFO) << "Audio is not supported in the answer.";
    }

    answer->AddContent(audio_content->name, audio_content->type, rejected,
                       audio_answer.release());
  } else {
    LOG(LS_INFO) << "Audio is not available in the offer.";
  }

  // Handle m=video.
  const ContentInfo* video_content = GetFirstVideoContent(offer);
  if (video_content) {
    scoped_ptr<TransportDescription> video_transport(
        CreateTransportAnswer(video_content->name, offer,
                              options.transport_options,
                              current_description));
    if (!video_transport) {
      return NULL;
    }

    scoped_ptr<VideoContentDescription> video_answer(
        new VideoContentDescription());
    // Do not require or create SDES cryptos if DTLS is used.
    cricket::SecurePolicy sdes_policy =
        video_transport->secure() ? cricket::SEC_DISABLED : secure();
    if (!CreateMediaContentAnswer(
            static_cast<const VideoContentDescription*>(
                video_content->description),
            options,
            video_codecs_,
            sdes_policy,
            GetCryptos(GetFirstVideoContentDescription(current_description)),
            video_rtp_extensions_,
            &current_streams,
            add_legacy_,
            bundle_enabled,
            video_answer.get())) {
      return NULL;
    }
    bool rejected = !options.has_video || video_content->rejected ||
        !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
                                  video_answer->protocol(),
                                  video_transport->secure());
    if (!rejected) {
      if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
                              answer.get())) {
        return NULL;
      }
      video_answer->set_bandwidth(options.video_bandwidth);
    } else {
      // RFC 3264
      // The answer MUST contain the same number of m-lines as the offer.
      LOG(LS_INFO) << "Video is not supported in the answer.";
    }
    answer->AddContent(video_content->name, video_content->type, rejected,
                       video_answer.release());
  } else {
    LOG(LS_INFO) << "Video is not available in the offer.";
  }

  // Handle m=data.
  const ContentInfo* data_content = GetFirstDataContent(offer);
  if (data_content) {
    scoped_ptr<TransportDescription> data_transport(
        CreateTransportAnswer(data_content->name, offer,
                              options.transport_options,
                              current_description));
    if (!data_transport) {
      return NULL;
    }
    bool is_sctp = (options.data_channel_type == DCT_SCTP);
    std::vector<DataCodec> data_codecs(data_codecs_);
    FilterDataCodecs(&data_codecs, is_sctp);

    scoped_ptr<DataContentDescription> data_answer(
        new DataContentDescription());
    // Do not require or create SDES cryptos if DTLS is used.
    cricket::SecurePolicy sdes_policy =
        data_transport->secure() ? cricket::SEC_DISABLED : secure();
    if (!CreateMediaContentAnswer(
            static_cast<const DataContentDescription*>(
                data_content->description),
            options,
            data_codecs_,
            sdes_policy,
            GetCryptos(GetFirstDataContentDescription(current_description)),
            RtpHeaderExtensions(),
            &current_streams,
            add_legacy_,
            bundle_enabled,
            data_answer.get())) {
      return NULL;  // Fails the session setup.
    }

    bool rejected = !options.has_data() || data_content->rejected ||
        !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
                                  data_answer->protocol(),
                                  data_transport->secure());
    if (!rejected) {
      data_answer->set_bandwidth(options.data_bandwidth);
      if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
                              answer.get())) {
        return NULL;
      }
    } else {
      // RFC 3264
      // The answer MUST contain the same number of m-lines as the offer.
      LOG(LS_INFO) << "Data is not supported in the answer.";
    }
    answer->AddContent(data_content->name, data_content->type, rejected,
                       data_answer.release());
  } else {
    LOG(LS_INFO) << "Data is not available in the offer.";
  }

  // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
  // group in the answer with the appropriate content names.
  if (offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled) {
    const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
    ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
    for (ContentInfos::const_iterator content = answer->contents().begin();
       content != answer->contents().end(); ++content) {
      if (!content->rejected && offer_bundle->HasContentName(content->name)) {
        answer_bundle.AddContentName(content->name);
      }
    }
    if (answer_bundle.FirstContentName()) {
      answer->AddGroup(answer_bundle);

      // Share the same ICE credentials and crypto params across all contents,
      // as BUNDLE requires.
      if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
        LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
        return NULL;
      }

      if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
        LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
        return NULL;
      }
    }
  }

  return answer.release();
}

void MediaSessionDescriptionFactory::GetCodecsToOffer(
    const SessionDescription* current_description,
    AudioCodecs* audio_codecs,
    VideoCodecs* video_codecs,
    DataCodecs* data_codecs) const {
  UsedPayloadTypes used_pltypes;
  audio_codecs->clear();
  video_codecs->clear();
  data_codecs->clear();


  // First - get all codecs from the current description if the media type
  // is used.
  // Add them to |used_pltypes| so the payloadtype is not reused if a new media
  // type is added.
  if (current_description) {
    const AudioContentDescription* audio =
        GetFirstAudioContentDescription(current_description);
    if (audio) {
      *audio_codecs = audio->codecs();
      used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
    }
    const VideoContentDescription* video =
        GetFirstVideoContentDescription(current_description);
    if (video) {
      *video_codecs = video->codecs();
      used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
    }
    const DataContentDescription* data =
        GetFirstDataContentDescription(current_description);
    if (data) {
      *data_codecs = data->codecs();
      used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
    }
  }

  // Add our codecs that are not in |current_description|.
  FindCodecsToOffer<AudioCodec>(audio_codecs_, audio_codecs, &used_pltypes);
  FindCodecsToOffer<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
  FindCodecsToOffer<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
}

void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
    const SessionDescription* current_description,
    RtpHeaderExtensions* audio_extensions,
    RtpHeaderExtensions* video_extensions) const {
  // All header extensions allocated from the same range to avoid potential
  // issues when using BUNDLE.
  UsedRtpHeaderExtensionIds used_ids;
  audio_extensions->clear();
  video_extensions->clear();

  // First - get all extensions from the current description if the media type
  // is used.
  // Add them to |used_ids| so the local ids are not reused if a new media
  // type is added.
  if (current_description) {
    const AudioContentDescription* audio =
        GetFirstAudioContentDescription(current_description);
    if (audio) {
      *audio_extensions = audio->rtp_header_extensions();
      used_ids.FindAndSetIdUsed(audio_extensions);
    }
    const VideoContentDescription* video =
        GetFirstVideoContentDescription(current_description);
    if (video) {
      *video_extensions = video->rtp_header_extensions();
      used_ids.FindAndSetIdUsed(video_extensions);
    }
  }

  // Add our default RTP header extensions that are not in
  // |current_description|.
  FindAndSetRtpHdrExtUsed(audio_rtp_header_extensions(), audio_extensions,
                          *video_extensions, &used_ids);
  FindAndSetRtpHdrExtUsed(video_rtp_header_extensions(), video_extensions,
                          *audio_extensions, &used_ids);
}

bool MediaSessionDescriptionFactory::AddTransportOffer(
  const std::string& content_name,
  const TransportOptions& transport_options,
  const SessionDescription* current_desc,
  SessionDescription* offer_desc) const {
  if (!transport_desc_factory_)
     return false;
  const TransportDescription* current_tdesc =
      GetTransportDescription(content_name, current_desc);
  talk_base::scoped_ptr<TransportDescription> new_tdesc(
      transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
  bool ret = (new_tdesc.get() != NULL &&
      offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
  if (!ret) {
    LOG(LS_ERROR)
        << "Failed to AddTransportOffer, content name=" << content_name;
  }
  return ret;
}

TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
    const std::string& content_name,
    const SessionDescription* offer_desc,
    const TransportOptions& transport_options,
    const SessionDescription* current_desc) const {
  if (!transport_desc_factory_)
    return NULL;
  const TransportDescription* offer_tdesc =
      GetTransportDescription(content_name, offer_desc);
  const TransportDescription* current_tdesc =
      GetTransportDescription(content_name, current_desc);
  return
      transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
                                            current_tdesc);
}

bool MediaSessionDescriptionFactory::AddTransportAnswer(
    const std::string& content_name,
    const TransportDescription& transport_desc,
    SessionDescription* answer_desc) const {
  if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
                                                   transport_desc))) {
    LOG(LS_ERROR)
        << "Failed to AddTransportAnswer, content name=" << content_name;
    return false;
  }
  return true;
}

bool IsMediaContent(const ContentInfo* content) {
  return (content &&
          (content->type == NS_JINGLE_RTP ||
           content->type == NS_JINGLE_DRAFT_SCTP));
}

bool IsAudioContent(const ContentInfo* content) {
  return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
}

bool IsVideoContent(const ContentInfo* content) {
  return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
}

bool IsDataContent(const ContentInfo* content) {
  return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
}

static const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
                                               MediaType media_type) {
  for (ContentInfos::const_iterator content = contents.begin();
       content != contents.end(); content++) {
    if (IsMediaContentOfType(&*content, media_type)) {
      return &*content;
    }
  }
  return NULL;
}

const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
  return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
}

const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
  return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
}

const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
  return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
}

static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
                                               MediaType media_type) {
  if (sdesc == NULL)
    return NULL;

  return GetFirstMediaContent(sdesc->contents(), media_type);
}

const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
  return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
}

const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
  return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
}

const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
  return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
}

const MediaContentDescription* GetFirstMediaContentDescription(
    const SessionDescription* sdesc, MediaType media_type) {
  const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
  const ContentDescription* description = content ? content->description : NULL;
  return static_cast<const MediaContentDescription*>(description);
}

const AudioContentDescription* GetFirstAudioContentDescription(
    const SessionDescription* sdesc) {
  return static_cast<const AudioContentDescription*>(
      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
}

const VideoContentDescription* GetFirstVideoContentDescription(
    const SessionDescription* sdesc) {
  return static_cast<const VideoContentDescription*>(
      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
}

const DataContentDescription* GetFirstDataContentDescription(
    const SessionDescription* sdesc) {
  return static_cast<const DataContentDescription*>(
      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
}

bool GetMediaChannelNameFromComponent(
    int component, MediaType media_type, std::string* channel_name) {
  if (media_type == MEDIA_TYPE_AUDIO) {
    if (component == ICE_CANDIDATE_COMPONENT_RTP) {
      *channel_name = GICE_CHANNEL_NAME_RTP;
      return true;
    } else if (component == ICE_CANDIDATE_COMPONENT_RTCP) {
      *channel_name = GICE_CHANNEL_NAME_RTCP;
      return true;
    }
  } else if (media_type == MEDIA_TYPE_VIDEO) {
    if (component == ICE_CANDIDATE_COMPONENT_RTP) {
      *channel_name = GICE_CHANNEL_NAME_VIDEO_RTP;
      return true;
    } else if (component == ICE_CANDIDATE_COMPONENT_RTCP) {
      *channel_name = GICE_CHANNEL_NAME_VIDEO_RTCP;
      return true;
    }
  } else if (media_type == MEDIA_TYPE_DATA) {
    if (component == ICE_CANDIDATE_COMPONENT_RTP) {
      *channel_name = GICE_CHANNEL_NAME_DATA_RTP;
      return true;
    } else if (component == ICE_CANDIDATE_COMPONENT_RTCP) {
      *channel_name = GICE_CHANNEL_NAME_DATA_RTCP;
      return true;
    }
  }

  return false;
}

bool GetMediaComponentFromChannelName(
    const std::string& channel_name, int* component) {
  if (channel_name == GICE_CHANNEL_NAME_RTP ||
      channel_name == GICE_CHANNEL_NAME_VIDEO_RTP ||
      channel_name == GICE_CHANNEL_NAME_DATA_RTP) {
    *component = ICE_CANDIDATE_COMPONENT_RTP;
    return true;
  } else if (channel_name == GICE_CHANNEL_NAME_RTCP ||
             channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP ||
             channel_name == GICE_CHANNEL_NAME_DATA_RTP) {
    *component = ICE_CANDIDATE_COMPONENT_RTCP;
    return true;
  }

  return false;
}

bool GetMediaTypeFromChannelName(
    const std::string& channel_name, MediaType* media_type) {
  if (channel_name == GICE_CHANNEL_NAME_RTP ||
      channel_name == GICE_CHANNEL_NAME_RTCP) {
    *media_type = MEDIA_TYPE_AUDIO;
    return true;
  } else if (channel_name == GICE_CHANNEL_NAME_VIDEO_RTP ||
             channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP) {
    *media_type = MEDIA_TYPE_VIDEO;
    return true;
  } else if (channel_name == GICE_CHANNEL_NAME_DATA_RTP ||
             channel_name == GICE_CHANNEL_NAME_DATA_RTCP) {
    *media_type = MEDIA_TYPE_DATA;
    return true;
  }

  return false;
}

}  // namespace cricket
