Home | History | Annotate | Download | only in media
      1 /*
      2  * libjingle
      3  * Copyright 2004 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/session/media/mediasession.h"
     29 
     30 #include <functional>
     31 #include <map>
     32 #include <set>
     33 #include <utility>
     34 
     35 #include "talk/media/base/constants.h"
     36 #include "talk/media/base/cryptoparams.h"
     37 #include "talk/session/media/channelmanager.h"
     38 #include "talk/session/media/srtpfilter.h"
     39 #include "webrtc/base/helpers.h"
     40 #include "webrtc/base/logging.h"
     41 #include "webrtc/base/scoped_ptr.h"
     42 #include "webrtc/base/stringutils.h"
     43 #include "webrtc/p2p/base/constants.h"
     44 
     45 #ifdef HAVE_SCTP
     46 #include "talk/media/sctp/sctpdataengine.h"
     47 #else
     48 static const uint32_t kMaxSctpSid = 1023;
     49 #endif
     50 
     51 namespace {
     52 const char kInline[] = "inline:";
     53 
     54 void GetSupportedCryptoSuiteNames(void (*func)(std::vector<int>*),
     55                                   std::vector<std::string>* names) {
     56 #ifdef HAVE_SRTP
     57   std::vector<int> crypto_suites;
     58   func(&crypto_suites);
     59   for (const auto crypto : crypto_suites) {
     60     names->push_back(rtc::SrtpCryptoSuiteToName(crypto));
     61   }
     62 #endif
     63 }
     64 }
     65 
     66 namespace cricket {
     67 
     68 using rtc::scoped_ptr;
     69 
     70 // RTP Profile names
     71 // http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xml
     72 // RFC4585
     73 const char kMediaProtocolAvpf[] = "RTP/AVPF";
     74 // RFC5124
     75 const char kMediaProtocolDtlsSavpf[] = "UDP/TLS/RTP/SAVPF";
     76 
     77 // We always generate offers with "UDP/TLS/RTP/SAVPF" when using DTLS-SRTP,
     78 // but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
     79 const char kMediaProtocolSavpf[] = "RTP/SAVPF";
     80 
     81 const char kMediaProtocolRtpPrefix[] = "RTP/";
     82 
     83 const char kMediaProtocolSctp[] = "SCTP";
     84 const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
     85 const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
     86 const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
     87 
     88 static bool IsMediaContentOfType(const ContentInfo* content,
     89                                  MediaType media_type) {
     90   if (!IsMediaContent(content)) {
     91     return false;
     92   }
     93 
     94   const MediaContentDescription* mdesc =
     95       static_cast<const MediaContentDescription*>(content->description);
     96   return mdesc && mdesc->type() == media_type;
     97 }
     98 
     99 static bool CreateCryptoParams(int tag, const std::string& cipher,
    100                                CryptoParams *out) {
    101   std::string key;
    102   key.reserve(SRTP_MASTER_KEY_BASE64_LEN);
    103 
    104   if (!rtc::CreateRandomString(SRTP_MASTER_KEY_BASE64_LEN, &key)) {
    105     return false;
    106   }
    107   out->tag = tag;
    108   out->cipher_suite = cipher;
    109   out->key_params = kInline;
    110   out->key_params += key;
    111   return true;
    112 }
    113 
    114 #ifdef HAVE_SRTP
    115 static bool AddCryptoParams(const std::string& cipher_suite,
    116                             CryptoParamsVec *out) {
    117   int size = static_cast<int>(out->size());
    118 
    119   out->resize(size + 1);
    120   return CreateCryptoParams(size, cipher_suite, &out->at(size));
    121 }
    122 
    123 void AddMediaCryptos(const CryptoParamsVec& cryptos,
    124                      MediaContentDescription* media) {
    125   for (CryptoParamsVec::const_iterator crypto = cryptos.begin();
    126        crypto != cryptos.end(); ++crypto) {
    127     media->AddCrypto(*crypto);
    128   }
    129 }
    130 
    131 bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
    132                         MediaContentDescription* media) {
    133   CryptoParamsVec cryptos;
    134   for (std::vector<std::string>::const_iterator it = crypto_suites.begin();
    135        it != crypto_suites.end(); ++it) {
    136     if (!AddCryptoParams(*it, &cryptos)) {
    137       return false;
    138     }
    139   }
    140   AddMediaCryptos(cryptos, media);
    141   return true;
    142 }
    143 #endif
    144 
    145 const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
    146   if (!media) {
    147     return NULL;
    148   }
    149   return &media->cryptos();
    150 }
    151 
    152 bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
    153                         const CryptoParams& crypto,
    154                         CryptoParams* out) {
    155   for (CryptoParamsVec::const_iterator it = cryptos.begin();
    156        it != cryptos.end(); ++it) {
    157     if (crypto.Matches(*it)) {
    158       *out = *it;
    159       return true;
    160     }
    161   }
    162   return false;
    163 }
    164 
    165 // For audio, HMAC 32 is prefered because of the low overhead.
    166 void GetSupportedAudioCryptoSuites(std::vector<int>* crypto_suites) {
    167 #ifdef HAVE_SRTP
    168   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_32);
    169   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
    170 #endif
    171 }
    172 
    173 void GetSupportedAudioCryptoSuiteNames(
    174     std::vector<std::string>* crypto_suite_names) {
    175   GetSupportedCryptoSuiteNames(GetSupportedAudioCryptoSuites,
    176                                crypto_suite_names);
    177 }
    178 
    179 void GetSupportedVideoCryptoSuites(std::vector<int>* crypto_suites) {
    180   GetDefaultSrtpCryptoSuites(crypto_suites);
    181 }
    182 
    183 void GetSupportedVideoCryptoSuiteNames(
    184     std::vector<std::string>* crypto_suite_names) {
    185   GetSupportedCryptoSuiteNames(GetSupportedVideoCryptoSuites,
    186                                crypto_suite_names);
    187 }
    188 
    189 void GetSupportedDataCryptoSuites(std::vector<int>* crypto_suites) {
    190   GetDefaultSrtpCryptoSuites(crypto_suites);
    191 }
    192 
    193 void GetSupportedDataCryptoSuiteNames(
    194     std::vector<std::string>* crypto_suite_names) {
    195   GetSupportedCryptoSuiteNames(GetSupportedDataCryptoSuites,
    196                                crypto_suite_names);
    197 }
    198 
    199 void GetDefaultSrtpCryptoSuites(std::vector<int>* crypto_suites) {
    200 #ifdef HAVE_SRTP
    201   crypto_suites->push_back(rtc::SRTP_AES128_CM_SHA1_80);
    202 #endif
    203 }
    204 
    205 void GetDefaultSrtpCryptoSuiteNames(
    206     std::vector<std::string>* crypto_suite_names) {
    207   GetSupportedCryptoSuiteNames(GetDefaultSrtpCryptoSuites, crypto_suite_names);
    208 }
    209 
    210 // For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is
    211 // tolerated unless bundle is enabled because it is low overhead. Pick the
    212 // crypto in the list that is supported.
    213 static bool SelectCrypto(const MediaContentDescription* offer,
    214                          bool bundle,
    215                          CryptoParams *crypto) {
    216   bool audio = offer->type() == MEDIA_TYPE_AUDIO;
    217   const CryptoParamsVec& cryptos = offer->cryptos();
    218 
    219   for (CryptoParamsVec::const_iterator i = cryptos.begin();
    220        i != cryptos.end(); ++i) {
    221     if (rtc::CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
    222         (rtc::CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio &&
    223          !bundle)) {
    224       return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
    225     }
    226   }
    227   return false;
    228 }
    229 
    230 static const StreamParams* FindFirstStreamParamsByCname(
    231     const StreamParamsVec& params_vec,
    232     const std::string& cname) {
    233   for (StreamParamsVec::const_iterator it = params_vec.begin();
    234        it != params_vec.end(); ++it) {
    235     if (cname == it->cname)
    236       return &*it;
    237   }
    238   return NULL;
    239 }
    240 
    241 // Generates a new CNAME or the CNAME of an already existing StreamParams
    242 // if a StreamParams exist for another Stream in streams with sync_label
    243 // sync_label.
    244 static bool GenerateCname(const StreamParamsVec& params_vec,
    245                           const MediaSessionOptions::Streams& streams,
    246                           const std::string& synch_label,
    247                           std::string* cname) {
    248   ASSERT(cname != NULL);
    249   if (!cname)
    250     return false;
    251 
    252   // Check if a CNAME exist for any of the other synched streams.
    253   for (MediaSessionOptions::Streams::const_iterator stream_it = streams.begin();
    254        stream_it != streams.end() ; ++stream_it) {
    255     if (synch_label != stream_it->sync_label)
    256       continue;
    257 
    258     // groupid is empty for StreamParams generated using
    259     // MediaSessionDescriptionFactory.
    260     const StreamParams* param = GetStreamByIds(params_vec, "", stream_it->id);
    261     if (param) {
    262       *cname = param->cname;
    263       return true;
    264     }
    265   }
    266   // No other stream seems to exist that we should sync with.
    267   // Generate a random string for the RTCP CNAME, as stated in RFC 6222.
    268   // This string is only used for synchronization, and therefore is opaque.
    269   do {
    270     if (!rtc::CreateRandomString(16, cname)) {
    271       ASSERT(false);
    272       return false;
    273     }
    274   } while (FindFirstStreamParamsByCname(params_vec, *cname));
    275 
    276   return true;
    277 }
    278 
    279 // Generate random SSRC values that are not already present in |params_vec|.
    280 // The generated values are added to |ssrcs|.
    281 // |num_ssrcs| is the number of the SSRC will be generated.
    282 static void GenerateSsrcs(const StreamParamsVec& params_vec,
    283                           int num_ssrcs,
    284                           std::vector<uint32_t>* ssrcs) {
    285   for (int i = 0; i < num_ssrcs; i++) {
    286     uint32_t candidate;
    287     do {
    288       candidate = rtc::CreateRandomNonZeroId();
    289     } while (GetStreamBySsrc(params_vec, candidate) ||
    290              std::count(ssrcs->begin(), ssrcs->end(), candidate) > 0);
    291     ssrcs->push_back(candidate);
    292   }
    293 }
    294 
    295 // Returns false if we exhaust the range of SIDs.
    296 static bool GenerateSctpSid(const StreamParamsVec& params_vec, uint32_t* sid) {
    297   if (params_vec.size() > kMaxSctpSid) {
    298     LOG(LS_WARNING) <<
    299         "Could not generate an SCTP SID: too many SCTP streams.";
    300     return false;
    301   }
    302   while (true) {
    303     uint32_t candidate = rtc::CreateRandomNonZeroId() % kMaxSctpSid;
    304     if (!GetStreamBySsrc(params_vec, candidate)) {
    305       *sid = candidate;
    306       return true;
    307     }
    308   }
    309 }
    310 
    311 static bool GenerateSctpSids(const StreamParamsVec& params_vec,
    312                              std::vector<uint32_t>* sids) {
    313   uint32_t sid;
    314   if (!GenerateSctpSid(params_vec, &sid)) {
    315     LOG(LS_WARNING) << "Could not generated an SCTP SID.";
    316     return false;
    317   }
    318   sids->push_back(sid);
    319   return true;
    320 }
    321 
    322 // Finds all StreamParams of all media types and attach them to stream_params.
    323 static void GetCurrentStreamParams(const SessionDescription* sdesc,
    324                                    StreamParamsVec* stream_params) {
    325   if (!sdesc)
    326     return;
    327 
    328   const ContentInfos& contents = sdesc->contents();
    329   for (ContentInfos::const_iterator content = contents.begin();
    330        content != contents.end(); ++content) {
    331     if (!IsMediaContent(&*content)) {
    332       continue;
    333     }
    334     const MediaContentDescription* media =
    335         static_cast<const MediaContentDescription*>(
    336             content->description);
    337     const StreamParamsVec& streams = media->streams();
    338     for (StreamParamsVec::const_iterator it = streams.begin();
    339          it != streams.end(); ++it) {
    340       stream_params->push_back(*it);
    341     }
    342   }
    343 }
    344 
    345 // Filters the data codecs for the data channel type.
    346 void FilterDataCodecs(std::vector<DataCodec>* codecs, bool sctp) {
    347   // Filter RTP codec for SCTP and vice versa.
    348   int codec_id = sctp ? kGoogleRtpDataCodecId : kGoogleSctpDataCodecId;
    349   for (std::vector<DataCodec>::iterator iter = codecs->begin();
    350        iter != codecs->end();) {
    351     if (iter->id == codec_id) {
    352       iter = codecs->erase(iter);
    353     } else {
    354       ++iter;
    355     }
    356   }
    357 }
    358 
    359 template <typename IdStruct>
    360 class UsedIds {
    361  public:
    362   UsedIds(int min_allowed_id, int max_allowed_id)
    363       : min_allowed_id_(min_allowed_id),
    364         max_allowed_id_(max_allowed_id),
    365         next_id_(max_allowed_id) {
    366   }
    367 
    368   // Loops through all Id in |ids| and changes its id if it is
    369   // already in use by another IdStruct. Call this methods with all Id
    370   // in a session description to make sure no duplicate ids exists.
    371   // Note that typename Id must be a type of IdStruct.
    372   template <typename Id>
    373   void FindAndSetIdUsed(std::vector<Id>* ids) {
    374     for (typename std::vector<Id>::iterator it = ids->begin();
    375          it != ids->end(); ++it) {
    376       FindAndSetIdUsed(&*it);
    377     }
    378   }
    379 
    380   // Finds and sets an unused id if the |idstruct| id is already in use.
    381   void FindAndSetIdUsed(IdStruct* idstruct) {
    382     const int original_id = idstruct->id;
    383     int new_id = idstruct->id;
    384 
    385     if (original_id > max_allowed_id_ || original_id < min_allowed_id_) {
    386       // If the original id is not in range - this is an id that can't be
    387       // dynamically changed.
    388       return;
    389     }
    390 
    391     if (IsIdUsed(original_id)) {
    392       new_id = FindUnusedId();
    393       LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id
    394           << " to " << new_id;
    395       idstruct->id = new_id;
    396     }
    397     SetIdUsed(new_id);
    398   }
    399 
    400  private:
    401   // Returns the first unused id in reverse order.
    402   // This hopefully reduce the risk of more collisions. We want to change the
    403   // default ids as little as possible.
    404   int FindUnusedId() {
    405     while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) {
    406       --next_id_;
    407     }
    408     ASSERT(next_id_ >= min_allowed_id_);
    409     return next_id_;
    410   }
    411 
    412   bool IsIdUsed(int new_id) {
    413     return id_set_.find(new_id) != id_set_.end();
    414   }
    415 
    416   void SetIdUsed(int new_id) {
    417     id_set_.insert(new_id);
    418   }
    419 
    420   const int min_allowed_id_;
    421   const int max_allowed_id_;
    422   int next_id_;
    423   std::set<int> id_set_;
    424 };
    425 
    426 // Helper class used for finding duplicate RTP payload types among audio, video
    427 // and data codecs. When bundle is used the payload types may not collide.
    428 class UsedPayloadTypes : public UsedIds<Codec> {
    429  public:
    430   UsedPayloadTypes()
    431       : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) {
    432   }
    433 
    434 
    435  private:
    436   static const int kDynamicPayloadTypeMin = 96;
    437   static const int kDynamicPayloadTypeMax = 127;
    438 };
    439 
    440 // Helper class used for finding duplicate RTP Header extension ids among
    441 // audio and video extensions.
    442 class UsedRtpHeaderExtensionIds : public UsedIds<RtpHeaderExtension> {
    443  public:
    444   UsedRtpHeaderExtensionIds()
    445       : UsedIds<RtpHeaderExtension>(kLocalIdMin, kLocalIdMax) {
    446   }
    447 
    448  private:
    449   // Min and Max local identifier for one-byte header extensions, per RFC5285.
    450   static const int kLocalIdMin = 1;
    451   static const int kLocalIdMax = 14;
    452 };
    453 
    454 static bool IsSctp(const MediaContentDescription* desc) {
    455   return ((desc->protocol() == kMediaProtocolSctp) ||
    456           (desc->protocol() == kMediaProtocolDtlsSctp));
    457 }
    458 
    459 // Adds a StreamParams for each Stream in Streams with media type
    460 // media_type to content_description.
    461 // |current_params| - All currently known StreamParams of any media type.
    462 template <class C>
    463 static bool AddStreamParams(
    464     MediaType media_type,
    465     const MediaSessionOptions::Streams& streams,
    466     StreamParamsVec* current_streams,
    467     MediaContentDescriptionImpl<C>* content_description,
    468     const bool add_legacy_stream) {
    469   const bool include_rtx_streams =
    470       ContainsRtxCodec(content_description->codecs());
    471 
    472   if (streams.empty() && add_legacy_stream) {
    473     // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
    474     std::vector<uint32_t> ssrcs;
    475     if (IsSctp(content_description)) {
    476       GenerateSctpSids(*current_streams, &ssrcs);
    477     } else {
    478       int num_ssrcs = include_rtx_streams ? 2 : 1;
    479       GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
    480     }
    481     if (include_rtx_streams) {
    482       content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
    483       content_description->set_multistream(true);
    484     } else {
    485       content_description->AddLegacyStream(ssrcs[0]);
    486     }
    487     return true;
    488   }
    489 
    490   MediaSessionOptions::Streams::const_iterator stream_it;
    491   for (stream_it = streams.begin();
    492        stream_it != streams.end(); ++stream_it) {
    493     if (stream_it->type != media_type)
    494       continue;  // Wrong media type.
    495 
    496     const StreamParams* param =
    497         GetStreamByIds(*current_streams, "", stream_it->id);
    498     // groupid is empty for StreamParams generated using
    499     // MediaSessionDescriptionFactory.
    500     if (!param) {
    501       // This is a new stream.
    502       // Get a CNAME. Either new or same as one of the other synched streams.
    503       std::string cname;
    504       if (!GenerateCname(*current_streams, streams, stream_it->sync_label,
    505                          &cname)) {
    506         return false;
    507       }
    508 
    509       std::vector<uint32_t> ssrcs;
    510       if (IsSctp(content_description)) {
    511         GenerateSctpSids(*current_streams, &ssrcs);
    512       } else {
    513         GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
    514       }
    515       StreamParams stream_param;
    516       stream_param.id = stream_it->id;
    517       // Add the generated ssrc.
    518       for (size_t i = 0; i < ssrcs.size(); ++i) {
    519         stream_param.ssrcs.push_back(ssrcs[i]);
    520       }
    521       if (stream_it->num_sim_layers > 1) {
    522         SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
    523         stream_param.ssrc_groups.push_back(group);
    524       }
    525       // Generate extra ssrcs for include_rtx_streams case.
    526       if (include_rtx_streams) {
    527         // Generate an RTX ssrc for every ssrc in the group.
    528         std::vector<uint32_t> rtx_ssrcs;
    529         GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()),
    530                       &rtx_ssrcs);
    531         for (size_t i = 0; i < ssrcs.size(); ++i) {
    532           stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]);
    533         }
    534         content_description->set_multistream(true);
    535       }
    536       stream_param.cname = cname;
    537       stream_param.sync_label = stream_it->sync_label;
    538       content_description->AddStream(stream_param);
    539 
    540       // Store the new StreamParams in current_streams.
    541       // This is necessary so that we can use the CNAME for other media types.
    542       current_streams->push_back(stream_param);
    543     } else {
    544       content_description->AddStream(*param);
    545     }
    546   }
    547   return true;
    548 }
    549 
    550 // Updates the transport infos of the |sdesc| according to the given
    551 // |bundle_group|. The transport infos of the content names within the
    552 // |bundle_group| should be updated to use the ufrag, pwd and DTLS role of the
    553 // first content within the |bundle_group|.
    554 static bool UpdateTransportInfoForBundle(const ContentGroup& bundle_group,
    555                                          SessionDescription* sdesc) {
    556   // The bundle should not be empty.
    557   if (!sdesc || !bundle_group.FirstContentName()) {
    558     return false;
    559   }
    560 
    561   // We should definitely have a transport for the first content.
    562   const std::string& selected_content_name = *bundle_group.FirstContentName();
    563   const TransportInfo* selected_transport_info =
    564       sdesc->GetTransportInfoByName(selected_content_name);
    565   if (!selected_transport_info) {
    566     return false;
    567   }
    568 
    569   // Set the other contents to use the same ICE credentials.
    570   const std::string& selected_ufrag =
    571       selected_transport_info->description.ice_ufrag;
    572   const std::string& selected_pwd =
    573       selected_transport_info->description.ice_pwd;
    574   ConnectionRole selected_connection_role =
    575       selected_transport_info->description.connection_role;
    576   for (TransportInfos::iterator it =
    577            sdesc->transport_infos().begin();
    578        it != sdesc->transport_infos().end(); ++it) {
    579     if (bundle_group.HasContentName(it->content_name) &&
    580         it->content_name != selected_content_name) {
    581       it->description.ice_ufrag = selected_ufrag;
    582       it->description.ice_pwd = selected_pwd;
    583       it->description.connection_role = selected_connection_role;
    584     }
    585   }
    586   return true;
    587 }
    588 
    589 // Gets the CryptoParamsVec of the given |content_name| from |sdesc|, and
    590 // sets it to |cryptos|.
    591 static bool GetCryptosByName(const SessionDescription* sdesc,
    592                              const std::string& content_name,
    593                              CryptoParamsVec* cryptos) {
    594   if (!sdesc || !cryptos) {
    595     return false;
    596   }
    597 
    598   const ContentInfo* content = sdesc->GetContentByName(content_name);
    599   if (!IsMediaContent(content) || !content->description) {
    600     return false;
    601   }
    602 
    603   const MediaContentDescription* media_desc =
    604       static_cast<const MediaContentDescription*>(content->description);
    605   *cryptos = media_desc->cryptos();
    606   return true;
    607 }
    608 
    609 // Predicate function used by the remove_if.
    610 // Returns true if the |crypto|'s cipher_suite is not found in |filter|.
    611 static bool CryptoNotFound(const CryptoParams crypto,
    612                            const CryptoParamsVec* filter) {
    613   if (filter == NULL) {
    614     return true;
    615   }
    616   for (CryptoParamsVec::const_iterator it = filter->begin();
    617        it != filter->end(); ++it) {
    618     if (it->cipher_suite == crypto.cipher_suite) {
    619       return false;
    620     }
    621   }
    622   return true;
    623 }
    624 
    625 // Prunes the |target_cryptos| by removing the crypto params (cipher_suite)
    626 // which are not available in |filter|.
    627 static void PruneCryptos(const CryptoParamsVec& filter,
    628                          CryptoParamsVec* target_cryptos) {
    629   if (!target_cryptos) {
    630     return;
    631   }
    632   target_cryptos->erase(std::remove_if(target_cryptos->begin(),
    633                                        target_cryptos->end(),
    634                                        bind2nd(ptr_fun(CryptoNotFound),
    635                                                &filter)),
    636                         target_cryptos->end());
    637 }
    638 
    639 static bool IsRtpProtocol(const std::string& protocol) {
    640   return protocol.empty() ||
    641          (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
    642 }
    643 
    644 static bool IsRtpContent(SessionDescription* sdesc,
    645                          const std::string& content_name) {
    646   bool is_rtp = false;
    647   ContentInfo* content = sdesc->GetContentByName(content_name);
    648   if (IsMediaContent(content)) {
    649     MediaContentDescription* media_desc =
    650         static_cast<MediaContentDescription*>(content->description);
    651     if (!media_desc) {
    652       return false;
    653     }
    654     is_rtp = IsRtpProtocol(media_desc->protocol());
    655   }
    656   return is_rtp;
    657 }
    658 
    659 // Updates the crypto parameters of the |sdesc| according to the given
    660 // |bundle_group|. The crypto parameters of all the contents within the
    661 // |bundle_group| should be updated to use the common subset of the
    662 // available cryptos.
    663 static bool UpdateCryptoParamsForBundle(const ContentGroup& bundle_group,
    664                                         SessionDescription* sdesc) {
    665   // The bundle should not be empty.
    666   if (!sdesc || !bundle_group.FirstContentName()) {
    667     return false;
    668   }
    669 
    670   bool common_cryptos_needed = false;
    671   // Get the common cryptos.
    672   const ContentNames& content_names = bundle_group.content_names();
    673   CryptoParamsVec common_cryptos;
    674   for (ContentNames::const_iterator it = content_names.begin();
    675        it != content_names.end(); ++it) {
    676     if (!IsRtpContent(sdesc, *it)) {
    677       continue;
    678     }
    679     // The common cryptos are needed if any of the content does not have DTLS
    680     // enabled.
    681     if (!sdesc->GetTransportInfoByName(*it)->description.secure()) {
    682       common_cryptos_needed = true;
    683     }
    684     if (it == content_names.begin()) {
    685       // Initial the common_cryptos with the first content in the bundle group.
    686       if (!GetCryptosByName(sdesc, *it, &common_cryptos)) {
    687         return false;
    688       }
    689       if (common_cryptos.empty()) {
    690         // If there's no crypto params, we should just return.
    691         return true;
    692       }
    693     } else {
    694       CryptoParamsVec cryptos;
    695       if (!GetCryptosByName(sdesc, *it, &cryptos)) {
    696         return false;
    697       }
    698       PruneCryptos(cryptos, &common_cryptos);
    699     }
    700   }
    701 
    702   if (common_cryptos.empty() && common_cryptos_needed) {
    703     return false;
    704   }
    705 
    706   // Update to use the common cryptos.
    707   for (ContentNames::const_iterator it = content_names.begin();
    708        it != content_names.end(); ++it) {
    709     if (!IsRtpContent(sdesc, *it)) {
    710       continue;
    711     }
    712     ContentInfo* content = sdesc->GetContentByName(*it);
    713     if (IsMediaContent(content)) {
    714       MediaContentDescription* media_desc =
    715           static_cast<MediaContentDescription*>(content->description);
    716       if (!media_desc) {
    717         return false;
    718       }
    719       media_desc->set_cryptos(common_cryptos);
    720     }
    721   }
    722   return true;
    723 }
    724 
    725 template <class C>
    726 static bool ContainsRtxCodec(const std::vector<C>& codecs) {
    727   typename std::vector<C>::const_iterator it;
    728   for (it = codecs.begin(); it != codecs.end(); ++it) {
    729     if (IsRtxCodec(*it)) {
    730       return true;
    731     }
    732   }
    733   return false;
    734 }
    735 
    736 template <class C>
    737 static bool IsRtxCodec(const C& codec) {
    738   return stricmp(codec.name.c_str(), kRtxCodecName) == 0;
    739 }
    740 
    741 // Create a media content to be offered in a session-initiate,
    742 // according to the given options.rtcp_mux, options.is_muc,
    743 // options.streams, codecs, secure_transport, crypto, and streams.  If we don't
    744 // currently have crypto (in current_cryptos) and it is enabled (in
    745 // secure_policy), crypto is created (according to crypto_suites).  If
    746 // add_legacy_stream is true, and current_streams is empty, a legacy
    747 // stream is created.  The created content is added to the offer.
    748 template <class C>
    749 static bool CreateMediaContentOffer(
    750     const MediaSessionOptions& options,
    751     const std::vector<C>& codecs,
    752     const SecurePolicy& secure_policy,
    753     const CryptoParamsVec* current_cryptos,
    754     const std::vector<std::string>& crypto_suites,
    755     const RtpHeaderExtensions& rtp_extensions,
    756     bool add_legacy_stream,
    757     StreamParamsVec* current_streams,
    758     MediaContentDescriptionImpl<C>* offer) {
    759   offer->AddCodecs(codecs);
    760   offer->SortCodecs();
    761 
    762   if (secure_policy == SEC_REQUIRED) {
    763     offer->set_crypto_required(CT_SDES);
    764   }
    765   offer->set_rtcp_mux(options.rtcp_mux_enabled);
    766   // TODO(deadbeef): Once we're sure this works correctly, enable it in
    767   // CreateOffer.
    768   // if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
    769   //   offer->set_rtcp_reduced_size(true);
    770   // }
    771   offer->set_multistream(options.is_muc);
    772   offer->set_rtp_header_extensions(rtp_extensions);
    773 
    774   if (!AddStreamParams(
    775           offer->type(), options.streams, current_streams,
    776           offer, add_legacy_stream)) {
    777     return false;
    778   }
    779 
    780 #ifdef HAVE_SRTP
    781   if (secure_policy != SEC_DISABLED) {
    782     if (current_cryptos) {
    783       AddMediaCryptos(*current_cryptos, offer);
    784     }
    785     if (offer->cryptos().empty()) {
    786       if (!CreateMediaCryptos(crypto_suites, offer)) {
    787         return false;
    788       }
    789     }
    790   }
    791 #endif
    792 
    793   if (offer->crypto_required() == CT_SDES && offer->cryptos().empty()) {
    794     return false;
    795   }
    796   return true;
    797 }
    798 
    799 template <class C>
    800 static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
    801                                   const std::string& codec1_id_str,
    802                                   const std::vector<C>& codecs2,
    803                                   const std::string& codec2_id_str) {
    804   int codec1_id;
    805   int codec2_id;
    806   C codec1;
    807   C codec2;
    808   if (!rtc::FromString(codec1_id_str, &codec1_id) ||
    809       !rtc::FromString(codec2_id_str, &codec2_id) ||
    810       !FindCodecById(codecs1, codec1_id, &codec1) ||
    811       !FindCodecById(codecs2, codec2_id, &codec2)) {
    812     return false;
    813   }
    814   return codec1.Matches(codec2);
    815 }
    816 
    817 template <class C>
    818 static void NegotiateCodecs(const std::vector<C>& local_codecs,
    819                             const std::vector<C>& offered_codecs,
    820                             std::vector<C>* negotiated_codecs) {
    821   typename std::vector<C>::const_iterator ours;
    822   for (ours = local_codecs.begin();
    823        ours != local_codecs.end(); ++ours) {
    824     typename std::vector<C>::const_iterator theirs;
    825     for (theirs = offered_codecs.begin();
    826          theirs != offered_codecs.end(); ++theirs) {
    827       if (ours->Matches(*theirs)) {
    828         C negotiated = *ours;
    829         negotiated.IntersectFeedbackParams(*theirs);
    830         if (IsRtxCodec(negotiated)) {
    831           std::string offered_apt_value;
    832           std::string local_apt_value;
    833           if (!ours->GetParam(kCodecParamAssociatedPayloadType,
    834                               &local_apt_value) ||
    835               !theirs->GetParam(kCodecParamAssociatedPayloadType,
    836                                 &offered_apt_value)) {
    837             LOG(LS_WARNING) << "RTX missing associated payload type.";
    838             continue;
    839           }
    840           // Only negotiate RTX if kCodecParamAssociatedPayloadType has been
    841           // set in local and remote codecs, and they match.
    842           if (!ReferencedCodecsMatch(local_codecs, local_apt_value,
    843                                      offered_codecs, offered_apt_value)) {
    844             LOG(LS_WARNING) << "RTX associated codecs don't match.";
    845             continue;
    846           }
    847           negotiated.SetParam(kCodecParamAssociatedPayloadType,
    848                               offered_apt_value);
    849         }
    850 
    851         negotiated.id = theirs->id;
    852         // RFC3264: Although the answerer MAY list the formats in their desired
    853         // order of preference, it is RECOMMENDED that unless there is a
    854         // specific reason, the answerer list formats in the same relative order
    855         // they were present in the offer.
    856         negotiated.preference = theirs->preference;
    857         negotiated_codecs->push_back(negotiated);
    858       }
    859     }
    860   }
    861 }
    862 
    863 template <class C>
    864 static bool FindMatchingCodec(const std::vector<C>& codecs,
    865                               const C& codec_to_match,
    866                               C* found_codec) {
    867   for (typename std::vector<C>::const_iterator it = codecs.begin();
    868        it  != codecs.end(); ++it) {
    869     if (it->Matches(codec_to_match)) {
    870       if (found_codec != NULL) {
    871         *found_codec= *it;
    872       }
    873       return true;
    874     }
    875   }
    876   return false;
    877 }
    878 
    879 // Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
    880 // already exist in |offered_codecs| and ensure the payload types don't
    881 // collide.
    882 template <class C>
    883 static void FindCodecsToOffer(
    884     const std::vector<C>& reference_codecs,
    885     std::vector<C>* offered_codecs,
    886     UsedPayloadTypes* used_pltypes) {
    887 
    888   typedef std::map<int, C> RtxCodecReferences;
    889   RtxCodecReferences new_rtx_codecs;
    890 
    891   // Find all new RTX codecs.
    892   for (typename std::vector<C>::const_iterator it = reference_codecs.begin();
    893        it != reference_codecs.end(); ++it) {
    894     if (!FindMatchingCodec<C>(*offered_codecs, *it, NULL) && IsRtxCodec(*it)) {
    895       C rtx_codec = *it;
    896       int referenced_pl_type =
    897           rtc::FromString<int>(0,
    898               rtx_codec.params[kCodecParamAssociatedPayloadType]);
    899       new_rtx_codecs.insert(std::pair<int, C>(referenced_pl_type,
    900                                               rtx_codec));
    901     }
    902   }
    903 
    904   // Add all new codecs that are not RTX codecs.
    905   for (typename std::vector<C>::const_iterator it = reference_codecs.begin();
    906        it != reference_codecs.end(); ++it) {
    907     if (!FindMatchingCodec<C>(*offered_codecs, *it, NULL) && !IsRtxCodec(*it)) {
    908       C codec = *it;
    909       int original_payload_id = codec.id;
    910       used_pltypes->FindAndSetIdUsed(&codec);
    911       offered_codecs->push_back(codec);
    912 
    913       // If this codec is referenced by a new RTX codec, update the reference
    914       // in the RTX codec with the new payload type.
    915       typename RtxCodecReferences::iterator rtx_it =
    916           new_rtx_codecs.find(original_payload_id);
    917       if (rtx_it != new_rtx_codecs.end()) {
    918         C& rtx_codec = rtx_it->second;
    919         rtx_codec.params[kCodecParamAssociatedPayloadType] =
    920             rtc::ToString(codec.id);
    921       }
    922     }
    923   }
    924 
    925   // Add all new RTX codecs.
    926   for (typename RtxCodecReferences::iterator it = new_rtx_codecs.begin();
    927        it != new_rtx_codecs.end(); ++it) {
    928     C& rtx_codec = it->second;
    929     used_pltypes->FindAndSetIdUsed(&rtx_codec);
    930     offered_codecs->push_back(rtx_codec);
    931   }
    932 }
    933 
    934 
    935 static bool FindByUri(const RtpHeaderExtensions& extensions,
    936                       const RtpHeaderExtension& ext_to_match,
    937                       RtpHeaderExtension* found_extension) {
    938   for (RtpHeaderExtensions::const_iterator it = extensions.begin();
    939        it  != extensions.end(); ++it) {
    940     // We assume that all URIs are given in a canonical format.
    941     if (it->uri == ext_to_match.uri) {
    942       if (found_extension != NULL) {
    943         *found_extension = *it;
    944       }
    945       return true;
    946     }
    947   }
    948   return false;
    949 }
    950 
    951 // Iterates through |offered_extensions|, adding each one to |all_extensions|
    952 // and |used_ids|, and resolving ID conflicts. If an offered extension has the
    953 // same URI as one in |all_extensions|, it will re-use the same ID and won't be
    954 // treated as a conflict.
    955 static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions,
    956                                     RtpHeaderExtensions* all_extensions,
    957                                     UsedRtpHeaderExtensionIds* used_ids) {
    958   for (auto& extension : *offered_extensions) {
    959     RtpHeaderExtension existing;
    960     if (FindByUri(*all_extensions, extension, &existing)) {
    961       extension.id = existing.id;
    962     } else {
    963       used_ids->FindAndSetIdUsed(&extension);
    964       all_extensions->push_back(extension);
    965     }
    966   }
    967 }
    968 
    969 // Adds |reference_extensions| to |offered_extensions|, while updating
    970 // |all_extensions| and |used_ids|.
    971 static void FindRtpHdrExtsToOffer(
    972     const RtpHeaderExtensions& reference_extensions,
    973     RtpHeaderExtensions* offered_extensions,
    974     RtpHeaderExtensions* all_extensions,
    975     UsedRtpHeaderExtensionIds* used_ids) {
    976   for (auto reference_extension : reference_extensions) {
    977     if (!FindByUri(*offered_extensions, reference_extension, NULL)) {
    978       RtpHeaderExtension existing;
    979       if (FindByUri(*all_extensions, reference_extension, &existing)) {
    980         offered_extensions->push_back(existing);
    981       } else {
    982         used_ids->FindAndSetIdUsed(&reference_extension);
    983         all_extensions->push_back(reference_extension);
    984         offered_extensions->push_back(reference_extension);
    985       }
    986     }
    987   }
    988 }
    989 
    990 static void NegotiateRtpHeaderExtensions(
    991     const RtpHeaderExtensions& local_extensions,
    992     const RtpHeaderExtensions& offered_extensions,
    993     RtpHeaderExtensions* negotiated_extenstions) {
    994   RtpHeaderExtensions::const_iterator ours;
    995   for (ours = local_extensions.begin();
    996        ours != local_extensions.end(); ++ours) {
    997     RtpHeaderExtension theirs;
    998     if (FindByUri(offered_extensions, *ours, &theirs)) {
    999       // We respond with their RTP header extension id.
   1000       negotiated_extenstions->push_back(theirs);
   1001     }
   1002   }
   1003 }
   1004 
   1005 static void StripCNCodecs(AudioCodecs* audio_codecs) {
   1006   AudioCodecs::iterator iter = audio_codecs->begin();
   1007   while (iter != audio_codecs->end()) {
   1008     if (stricmp(iter->name.c_str(), kComfortNoiseCodecName) == 0) {
   1009       iter = audio_codecs->erase(iter);
   1010     } else {
   1011       ++iter;
   1012     }
   1013   }
   1014 }
   1015 
   1016 // Create a media content to be answered in a session-accept,
   1017 // according to the given options.rtcp_mux, options.streams, codecs,
   1018 // crypto, and streams.  If we don't currently have crypto (in
   1019 // current_cryptos) and it is enabled (in secure_policy), crypto is
   1020 // created (according to crypto_suites).  If add_legacy_stream is
   1021 // true, and current_streams is empty, a legacy stream is created.
   1022 // The codecs, rtcp_mux, and crypto are all negotiated with the offer
   1023 // from the incoming session-initiate.  If the negotiation fails, this
   1024 // method returns false.  The created content is added to the offer.
   1025 template <class C>
   1026 static bool CreateMediaContentAnswer(
   1027     const MediaContentDescriptionImpl<C>* offer,
   1028     const MediaSessionOptions& options,
   1029     const std::vector<C>& local_codecs,
   1030     const SecurePolicy& sdes_policy,
   1031     const CryptoParamsVec* current_cryptos,
   1032     const RtpHeaderExtensions& local_rtp_extenstions,
   1033     StreamParamsVec* current_streams,
   1034     bool add_legacy_stream,
   1035     bool bundle_enabled,
   1036     MediaContentDescriptionImpl<C>* answer) {
   1037   std::vector<C> negotiated_codecs;
   1038   NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
   1039   answer->AddCodecs(negotiated_codecs);
   1040   answer->SortCodecs();
   1041   answer->set_protocol(offer->protocol());
   1042   RtpHeaderExtensions negotiated_rtp_extensions;
   1043   NegotiateRtpHeaderExtensions(local_rtp_extenstions,
   1044                                offer->rtp_header_extensions(),
   1045                                &negotiated_rtp_extensions);
   1046   answer->set_rtp_header_extensions(negotiated_rtp_extensions);
   1047 
   1048   answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());
   1049   // TODO(deadbeef): Once we're sure this works correctly, enable it in
   1050   // CreateAnswer.
   1051   // if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
   1052   //   answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
   1053   // }
   1054 
   1055   if (sdes_policy != SEC_DISABLED) {
   1056     CryptoParams crypto;
   1057     if (SelectCrypto(offer, bundle_enabled, &crypto)) {
   1058       if (current_cryptos) {
   1059         FindMatchingCrypto(*current_cryptos, crypto, &crypto);
   1060       }
   1061       answer->AddCrypto(crypto);
   1062     }
   1063   }
   1064 
   1065   if (answer->cryptos().empty() &&
   1066       (offer->crypto_required() == CT_SDES || sdes_policy == SEC_REQUIRED)) {
   1067     return false;
   1068   }
   1069 
   1070   if (!AddStreamParams(
   1071           answer->type(), options.streams, current_streams,
   1072           answer, add_legacy_stream)) {
   1073     return false;  // Something went seriously wrong.
   1074   }
   1075 
   1076   // Make sure the answer media content direction is per default set as
   1077   // described in RFC3264 section 6.1.
   1078   switch (offer->direction()) {
   1079     case MD_INACTIVE:
   1080       answer->set_direction(MD_INACTIVE);
   1081       break;
   1082     case MD_SENDONLY:
   1083       answer->set_direction(MD_RECVONLY);
   1084       break;
   1085     case MD_RECVONLY:
   1086       answer->set_direction(IsRtpProtocol(answer->protocol()) &&
   1087                                     answer->streams().empty()
   1088                                 ? MD_INACTIVE
   1089                                 : MD_SENDONLY);
   1090       break;
   1091     case MD_SENDRECV:
   1092       answer->set_direction(IsRtpProtocol(answer->protocol()) &&
   1093                                     answer->streams().empty()
   1094                                 ? MD_RECVONLY
   1095                                 : MD_SENDRECV);
   1096       break;
   1097     default:
   1098       RTC_DCHECK(false && "MediaContentDescription has unexpected direction.");
   1099       break;
   1100   }
   1101 
   1102   return true;
   1103 }
   1104 
   1105 static bool IsMediaProtocolSupported(MediaType type,
   1106                                      const std::string& protocol,
   1107                                      bool secure_transport) {
   1108   // Data channels can have a protocol of SCTP or SCTP/DTLS.
   1109   if (type == MEDIA_TYPE_DATA &&
   1110       ((protocol == kMediaProtocolSctp && !secure_transport)||
   1111        (protocol == kMediaProtocolDtlsSctp && secure_transport))) {
   1112     return true;
   1113   }
   1114 
   1115   // Since not all applications serialize and deserialize the media protocol,
   1116   // we will have to accept |protocol| to be empty.
   1117   return protocol == kMediaProtocolAvpf || protocol.empty() ||
   1118       protocol == kMediaProtocolSavpf ||
   1119       (protocol == kMediaProtocolDtlsSavpf && secure_transport);
   1120 }
   1121 
   1122 static void SetMediaProtocol(bool secure_transport,
   1123                              MediaContentDescription* desc) {
   1124   if (!desc->cryptos().empty())
   1125     desc->set_protocol(kMediaProtocolSavpf);
   1126   else if (secure_transport)
   1127     desc->set_protocol(kMediaProtocolDtlsSavpf);
   1128   else
   1129     desc->set_protocol(kMediaProtocolAvpf);
   1130 }
   1131 
   1132 // Gets the TransportInfo of the given |content_name| from the
   1133 // |current_description|. If doesn't exist, returns a new one.
   1134 static const TransportDescription* GetTransportDescription(
   1135     const std::string& content_name,
   1136     const SessionDescription* current_description) {
   1137   const TransportDescription* desc = NULL;
   1138   if (current_description) {
   1139     const TransportInfo* info =
   1140         current_description->GetTransportInfoByName(content_name);
   1141     if (info) {
   1142       desc = &info->description;
   1143     }
   1144   }
   1145   return desc;
   1146 }
   1147 
   1148 // Gets the current DTLS state from the transport description.
   1149 static bool IsDtlsActive(
   1150     const std::string& content_name,
   1151     const SessionDescription* current_description) {
   1152   if (!current_description)
   1153     return false;
   1154 
   1155   const ContentInfo* content =
   1156       current_description->GetContentByName(content_name);
   1157   if (!content)
   1158     return false;
   1159 
   1160   const TransportDescription* current_tdesc =
   1161       GetTransportDescription(content_name, current_description);
   1162   if (!current_tdesc)
   1163     return false;
   1164 
   1165   return current_tdesc->secure();
   1166 }
   1167 
   1168 std::string MediaTypeToString(MediaType type) {
   1169   std::string type_str;
   1170   switch (type) {
   1171     case MEDIA_TYPE_AUDIO:
   1172       type_str = "audio";
   1173       break;
   1174     case MEDIA_TYPE_VIDEO:
   1175       type_str = "video";
   1176       break;
   1177     case MEDIA_TYPE_DATA:
   1178       type_str = "data";
   1179       break;
   1180     default:
   1181       ASSERT(false);
   1182       break;
   1183   }
   1184   return type_str;
   1185 }
   1186 
   1187 void MediaSessionOptions::AddSendStream(MediaType type,
   1188                                     const std::string& id,
   1189                                     const std::string& sync_label) {
   1190   AddSendStreamInternal(type, id, sync_label, 1);
   1191 }
   1192 
   1193 void MediaSessionOptions::AddSendVideoStream(
   1194     const std::string& id,
   1195     const std::string& sync_label,
   1196     int num_sim_layers) {
   1197   AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
   1198 }
   1199 
   1200 void MediaSessionOptions::AddSendStreamInternal(
   1201     MediaType type,
   1202     const std::string& id,
   1203     const std::string& sync_label,
   1204     int num_sim_layers) {
   1205   streams.push_back(Stream(type, id, sync_label, num_sim_layers));
   1206 
   1207   // If we haven't already set the data_channel_type, and we add a
   1208   // stream, we assume it's an RTP data stream.
   1209   if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
   1210     data_channel_type = DCT_RTP;
   1211 }
   1212 
   1213 void MediaSessionOptions::RemoveSendStream(MediaType type,
   1214                                        const std::string& id) {
   1215   Streams::iterator stream_it = streams.begin();
   1216   for (; stream_it != streams.end(); ++stream_it) {
   1217     if (stream_it->type == type && stream_it->id == id) {
   1218       streams.erase(stream_it);
   1219       return;
   1220     }
   1221   }
   1222   ASSERT(false);
   1223 }
   1224 
   1225 bool MediaSessionOptions::HasSendMediaStream(MediaType type) const {
   1226   Streams::const_iterator stream_it = streams.begin();
   1227   for (; stream_it != streams.end(); ++stream_it) {
   1228     if (stream_it->type == type) {
   1229       return true;
   1230     }
   1231   }
   1232   return false;
   1233 }
   1234 
   1235 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
   1236     const TransportDescriptionFactory* transport_desc_factory)
   1237     : secure_(SEC_DISABLED),
   1238       add_legacy_(true),
   1239       transport_desc_factory_(transport_desc_factory) {
   1240 }
   1241 
   1242 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
   1243     ChannelManager* channel_manager,
   1244     const TransportDescriptionFactory* transport_desc_factory)
   1245     : secure_(SEC_DISABLED),
   1246       add_legacy_(true),
   1247       transport_desc_factory_(transport_desc_factory) {
   1248   channel_manager->GetSupportedAudioCodecs(&audio_codecs_);
   1249   channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
   1250   channel_manager->GetSupportedVideoCodecs(&video_codecs_);
   1251   channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
   1252   channel_manager->GetSupportedDataCodecs(&data_codecs_);
   1253 }
   1254 
   1255 SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
   1256     const MediaSessionOptions& options,
   1257     const SessionDescription* current_description) const {
   1258   scoped_ptr<SessionDescription> offer(new SessionDescription());
   1259 
   1260   StreamParamsVec current_streams;
   1261   GetCurrentStreamParams(current_description, &current_streams);
   1262 
   1263   AudioCodecs audio_codecs;
   1264   VideoCodecs video_codecs;
   1265   DataCodecs data_codecs;
   1266   GetCodecsToOffer(current_description, &audio_codecs, &video_codecs,
   1267                    &data_codecs);
   1268 
   1269   if (!options.vad_enabled) {
   1270     // If application doesn't want CN codecs in offer.
   1271     StripCNCodecs(&audio_codecs);
   1272   }
   1273 
   1274   RtpHeaderExtensions audio_rtp_extensions;
   1275   RtpHeaderExtensions video_rtp_extensions;
   1276   GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
   1277                        &video_rtp_extensions);
   1278 
   1279   bool audio_added = false;
   1280   bool video_added = false;
   1281   bool data_added = false;
   1282 
   1283   // Iterate through the contents of |current_description| to maintain the order
   1284   // of the m-lines in the new offer.
   1285   if (current_description) {
   1286     ContentInfos::const_iterator it = current_description->contents().begin();
   1287     for (; it != current_description->contents().end(); ++it) {
   1288       if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
   1289         if (!AddAudioContentForOffer(options, current_description,
   1290                                      audio_rtp_extensions, audio_codecs,
   1291                                      &current_streams, offer.get())) {
   1292           return NULL;
   1293         }
   1294         audio_added = true;
   1295       } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
   1296         if (!AddVideoContentForOffer(options, current_description,
   1297                                      video_rtp_extensions, video_codecs,
   1298                                      &current_streams, offer.get())) {
   1299           return NULL;
   1300         }
   1301         video_added = true;
   1302       } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) {
   1303         MediaSessionOptions options_copy(options);
   1304         if (IsSctp(static_cast<const MediaContentDescription*>(
   1305                 it->description))) {
   1306           options_copy.data_channel_type = DCT_SCTP;
   1307         }
   1308         if (!AddDataContentForOffer(options_copy, current_description,
   1309                                     &data_codecs, &current_streams,
   1310                                     offer.get())) {
   1311           return NULL;
   1312         }
   1313         data_added = true;
   1314       } else {
   1315         ASSERT(false);
   1316       }
   1317     }
   1318   }
   1319 
   1320   // Append contents that are not in |current_description|.
   1321   if (!audio_added && options.has_audio() &&
   1322       !AddAudioContentForOffer(options, current_description,
   1323                                audio_rtp_extensions, audio_codecs,
   1324                                &current_streams, offer.get())) {
   1325     return NULL;
   1326   }
   1327   if (!video_added && options.has_video() &&
   1328       !AddVideoContentForOffer(options, current_description,
   1329                                video_rtp_extensions, video_codecs,
   1330                                &current_streams, offer.get())) {
   1331     return NULL;
   1332   }
   1333   if (!data_added && options.has_data() &&
   1334       !AddDataContentForOffer(options, current_description, &data_codecs,
   1335                               &current_streams, offer.get())) {
   1336     return NULL;
   1337   }
   1338 
   1339   // Bundle the contents together, if we've been asked to do so, and update any
   1340   // parameters that need to be tweaked for BUNDLE.
   1341   if (options.bundle_enabled) {
   1342     ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
   1343     for (ContentInfos::const_iterator content = offer->contents().begin();
   1344        content != offer->contents().end(); ++content) {
   1345       offer_bundle.AddContentName(content->name);
   1346     }
   1347     offer->AddGroup(offer_bundle);
   1348     if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
   1349       LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
   1350       return NULL;
   1351     }
   1352     if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
   1353       LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
   1354       return NULL;
   1355     }
   1356   }
   1357 
   1358   return offer.release();
   1359 }
   1360 
   1361 SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
   1362     const SessionDescription* offer, const MediaSessionOptions& options,
   1363     const SessionDescription* current_description) const {
   1364   // The answer contains the intersection of the codecs in the offer with the
   1365   // codecs we support, ordered by our local preference. As indicated by
   1366   // XEP-0167, we retain the same payload ids from the offer in the answer.
   1367   scoped_ptr<SessionDescription> answer(new SessionDescription());
   1368 
   1369   StreamParamsVec current_streams;
   1370   GetCurrentStreamParams(current_description, &current_streams);
   1371 
   1372   if (offer) {
   1373     ContentInfos::const_iterator it = offer->contents().begin();
   1374     for (; it != offer->contents().end(); ++it) {
   1375       if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
   1376         if (!AddAudioContentForAnswer(offer, options, current_description,
   1377                                   &current_streams, answer.get())) {
   1378           return NULL;
   1379         }
   1380       } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
   1381         if (!AddVideoContentForAnswer(offer, options, current_description,
   1382                                       &current_streams, answer.get())) {
   1383           return NULL;
   1384         }
   1385       } else {
   1386         ASSERT(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA));
   1387         if (!AddDataContentForAnswer(offer, options, current_description,
   1388                                      &current_streams, answer.get())) {
   1389           return NULL;
   1390         }
   1391       }
   1392     }
   1393   }
   1394 
   1395   // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
   1396   // group in the answer with the appropriate content names.
   1397   if (offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled) {
   1398     const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
   1399     ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
   1400     for (ContentInfos::const_iterator content = answer->contents().begin();
   1401        content != answer->contents().end(); ++content) {
   1402       if (!content->rejected && offer_bundle->HasContentName(content->name)) {
   1403         answer_bundle.AddContentName(content->name);
   1404       }
   1405     }
   1406     if (answer_bundle.FirstContentName()) {
   1407       answer->AddGroup(answer_bundle);
   1408 
   1409       // Share the same ICE credentials and crypto params across all contents,
   1410       // as BUNDLE requires.
   1411       if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) {
   1412         LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle.";
   1413         return NULL;
   1414       }
   1415 
   1416       if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) {
   1417         LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle.";
   1418         return NULL;
   1419       }
   1420     }
   1421   }
   1422 
   1423   return answer.release();
   1424 }
   1425 
   1426 void MediaSessionDescriptionFactory::GetCodecsToOffer(
   1427     const SessionDescription* current_description,
   1428     AudioCodecs* audio_codecs,
   1429     VideoCodecs* video_codecs,
   1430     DataCodecs* data_codecs) const {
   1431   UsedPayloadTypes used_pltypes;
   1432   audio_codecs->clear();
   1433   video_codecs->clear();
   1434   data_codecs->clear();
   1435 
   1436 
   1437   // First - get all codecs from the current description if the media type
   1438   // is used.
   1439   // Add them to |used_pltypes| so the payloadtype is not reused if a new media
   1440   // type is added.
   1441   if (current_description) {
   1442     const AudioContentDescription* audio =
   1443         GetFirstAudioContentDescription(current_description);
   1444     if (audio) {
   1445       *audio_codecs = audio->codecs();
   1446       used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
   1447     }
   1448     const VideoContentDescription* video =
   1449         GetFirstVideoContentDescription(current_description);
   1450     if (video) {
   1451       *video_codecs = video->codecs();
   1452       used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
   1453     }
   1454     const DataContentDescription* data =
   1455         GetFirstDataContentDescription(current_description);
   1456     if (data) {
   1457       *data_codecs = data->codecs();
   1458       used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
   1459     }
   1460   }
   1461 
   1462   // Add our codecs that are not in |current_description|.
   1463   FindCodecsToOffer<AudioCodec>(audio_codecs_, audio_codecs, &used_pltypes);
   1464   FindCodecsToOffer<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
   1465   FindCodecsToOffer<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
   1466 }
   1467 
   1468 void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
   1469     const SessionDescription* current_description,
   1470     RtpHeaderExtensions* audio_extensions,
   1471     RtpHeaderExtensions* video_extensions) const {
   1472   // All header extensions allocated from the same range to avoid potential
   1473   // issues when using BUNDLE.
   1474   UsedRtpHeaderExtensionIds used_ids;
   1475   RtpHeaderExtensions all_extensions;
   1476   audio_extensions->clear();
   1477   video_extensions->clear();
   1478 
   1479   // First - get all extensions from the current description if the media type
   1480   // is used.
   1481   // Add them to |used_ids| so the local ids are not reused if a new media
   1482   // type is added.
   1483   if (current_description) {
   1484     const AudioContentDescription* audio =
   1485         GetFirstAudioContentDescription(current_description);
   1486     if (audio) {
   1487       *audio_extensions = audio->rtp_header_extensions();
   1488       FindAndSetRtpHdrExtUsed(audio_extensions, &all_extensions, &used_ids);
   1489     }
   1490     const VideoContentDescription* video =
   1491         GetFirstVideoContentDescription(current_description);
   1492     if (video) {
   1493       *video_extensions = video->rtp_header_extensions();
   1494       FindAndSetRtpHdrExtUsed(video_extensions, &all_extensions, &used_ids);
   1495     }
   1496   }
   1497 
   1498   // Add our default RTP header extensions that are not in
   1499   // |current_description|.
   1500   FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions,
   1501                         &all_extensions, &used_ids);
   1502   FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions,
   1503                         &all_extensions, &used_ids);
   1504 }
   1505 
   1506 bool MediaSessionDescriptionFactory::AddTransportOffer(
   1507   const std::string& content_name,
   1508   const TransportOptions& transport_options,
   1509   const SessionDescription* current_desc,
   1510   SessionDescription* offer_desc) const {
   1511   if (!transport_desc_factory_)
   1512      return false;
   1513   const TransportDescription* current_tdesc =
   1514       GetTransportDescription(content_name, current_desc);
   1515   rtc::scoped_ptr<TransportDescription> new_tdesc(
   1516       transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
   1517   bool ret = (new_tdesc.get() != NULL &&
   1518       offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
   1519   if (!ret) {
   1520     LOG(LS_ERROR)
   1521         << "Failed to AddTransportOffer, content name=" << content_name;
   1522   }
   1523   return ret;
   1524 }
   1525 
   1526 TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer(
   1527     const std::string& content_name,
   1528     const SessionDescription* offer_desc,
   1529     const TransportOptions& transport_options,
   1530     const SessionDescription* current_desc) const {
   1531   if (!transport_desc_factory_)
   1532     return NULL;
   1533   const TransportDescription* offer_tdesc =
   1534       GetTransportDescription(content_name, offer_desc);
   1535   const TransportDescription* current_tdesc =
   1536       GetTransportDescription(content_name, current_desc);
   1537   return
   1538       transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
   1539                                             current_tdesc);
   1540 }
   1541 
   1542 bool MediaSessionDescriptionFactory::AddTransportAnswer(
   1543     const std::string& content_name,
   1544     const TransportDescription& transport_desc,
   1545     SessionDescription* answer_desc) const {
   1546   if (!answer_desc->AddTransportInfo(TransportInfo(content_name,
   1547                                                    transport_desc))) {
   1548     LOG(LS_ERROR)
   1549         << "Failed to AddTransportAnswer, content name=" << content_name;
   1550     return false;
   1551   }
   1552   return true;
   1553 }
   1554 
   1555 bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
   1556     const MediaSessionOptions& options,
   1557     const SessionDescription* current_description,
   1558     const RtpHeaderExtensions& audio_rtp_extensions,
   1559     const AudioCodecs& audio_codecs,
   1560     StreamParamsVec* current_streams,
   1561     SessionDescription* desc) const {
   1562   const ContentInfo* current_audio_content =
   1563       GetFirstAudioContent(current_description);
   1564   std::string content_name =
   1565       current_audio_content ? current_audio_content->name : CN_AUDIO;
   1566 
   1567   cricket::SecurePolicy sdes_policy =
   1568       IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
   1569                                                       : secure();
   1570 
   1571   scoped_ptr<AudioContentDescription> audio(new AudioContentDescription());
   1572   std::vector<std::string> crypto_suites;
   1573   GetSupportedAudioCryptoSuiteNames(&crypto_suites);
   1574   if (!CreateMediaContentOffer(
   1575           options,
   1576           audio_codecs,
   1577           sdes_policy,
   1578           GetCryptos(GetFirstAudioContentDescription(current_description)),
   1579           crypto_suites,
   1580           audio_rtp_extensions,
   1581           add_legacy_,
   1582           current_streams,
   1583           audio.get())) {
   1584     return false;
   1585   }
   1586   audio->set_lang(lang_);
   1587 
   1588   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
   1589   SetMediaProtocol(secure_transport, audio.get());
   1590 
   1591   if (!audio->streams().empty()) {
   1592     if (options.recv_audio) {
   1593       audio->set_direction(MD_SENDRECV);
   1594     } else {
   1595       audio->set_direction(MD_SENDONLY);
   1596     }
   1597   } else {
   1598     if (options.recv_audio) {
   1599       audio->set_direction(MD_RECVONLY);
   1600     } else {
   1601       audio->set_direction(MD_INACTIVE);
   1602     }
   1603   }
   1604 
   1605   desc->AddContent(content_name, NS_JINGLE_RTP, audio.release());
   1606   if (!AddTransportOffer(content_name, options.audio_transport_options,
   1607                          current_description, desc)) {
   1608     return false;
   1609   }
   1610 
   1611   return true;
   1612 }
   1613 
   1614 bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
   1615     const MediaSessionOptions& options,
   1616     const SessionDescription* current_description,
   1617     const RtpHeaderExtensions& video_rtp_extensions,
   1618     const VideoCodecs& video_codecs,
   1619     StreamParamsVec* current_streams,
   1620     SessionDescription* desc) const {
   1621   const ContentInfo* current_video_content =
   1622       GetFirstVideoContent(current_description);
   1623   std::string content_name =
   1624       current_video_content ? current_video_content->name : CN_VIDEO;
   1625 
   1626   cricket::SecurePolicy sdes_policy =
   1627       IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
   1628                                                       : secure();
   1629 
   1630   scoped_ptr<VideoContentDescription> video(new VideoContentDescription());
   1631   std::vector<std::string> crypto_suites;
   1632   GetSupportedVideoCryptoSuiteNames(&crypto_suites);
   1633   if (!CreateMediaContentOffer(
   1634           options,
   1635           video_codecs,
   1636           sdes_policy,
   1637           GetCryptos(GetFirstVideoContentDescription(current_description)),
   1638           crypto_suites,
   1639           video_rtp_extensions,
   1640           add_legacy_,
   1641           current_streams,
   1642           video.get())) {
   1643     return false;
   1644   }
   1645 
   1646   video->set_bandwidth(options.video_bandwidth);
   1647 
   1648   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
   1649   SetMediaProtocol(secure_transport, video.get());
   1650 
   1651   if (!video->streams().empty()) {
   1652     if (options.recv_video) {
   1653       video->set_direction(MD_SENDRECV);
   1654     } else {
   1655       video->set_direction(MD_SENDONLY);
   1656     }
   1657   } else {
   1658     if (options.recv_video) {
   1659       video->set_direction(MD_RECVONLY);
   1660     } else {
   1661       video->set_direction(MD_INACTIVE);
   1662     }
   1663   }
   1664 
   1665   desc->AddContent(content_name, NS_JINGLE_RTP, video.release());
   1666   if (!AddTransportOffer(content_name, options.video_transport_options,
   1667                          current_description, desc)) {
   1668     return false;
   1669   }
   1670 
   1671   return true;
   1672 }
   1673 
   1674 bool MediaSessionDescriptionFactory::AddDataContentForOffer(
   1675     const MediaSessionOptions& options,
   1676     const SessionDescription* current_description,
   1677     DataCodecs* data_codecs,
   1678     StreamParamsVec* current_streams,
   1679     SessionDescription* desc) const {
   1680   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
   1681 
   1682   scoped_ptr<DataContentDescription> data(new DataContentDescription());
   1683   bool is_sctp = (options.data_channel_type == DCT_SCTP);
   1684 
   1685   FilterDataCodecs(data_codecs, is_sctp);
   1686 
   1687   const ContentInfo* current_data_content =
   1688       GetFirstDataContent(current_description);
   1689   std::string content_name =
   1690       current_data_content ? current_data_content->name : CN_DATA;
   1691 
   1692   cricket::SecurePolicy sdes_policy =
   1693       IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
   1694                                                       : secure();
   1695   std::vector<std::string> crypto_suites;
   1696   if (is_sctp) {
   1697     // SDES doesn't make sense for SCTP, so we disable it, and we only
   1698     // get SDES crypto suites for RTP-based data channels.
   1699     sdes_policy = cricket::SEC_DISABLED;
   1700     // Unlike SetMediaProtocol below, we need to set the protocol
   1701     // before we call CreateMediaContentOffer.  Otherwise,
   1702     // CreateMediaContentOffer won't know this is SCTP and will
   1703     // generate SSRCs rather than SIDs.
   1704     data->set_protocol(
   1705         secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
   1706   } else {
   1707     GetSupportedDataCryptoSuiteNames(&crypto_suites);
   1708   }
   1709 
   1710   if (!CreateMediaContentOffer(
   1711           options,
   1712           *data_codecs,
   1713           sdes_policy,
   1714           GetCryptos(GetFirstDataContentDescription(current_description)),
   1715           crypto_suites,
   1716           RtpHeaderExtensions(),
   1717           add_legacy_,
   1718           current_streams,
   1719           data.get())) {
   1720     return false;
   1721   }
   1722 
   1723   if (is_sctp) {
   1724     desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release());
   1725   } else {
   1726     data->set_bandwidth(options.data_bandwidth);
   1727     SetMediaProtocol(secure_transport, data.get());
   1728     desc->AddContent(content_name, NS_JINGLE_RTP, data.release());
   1729   }
   1730   if (!AddTransportOffer(content_name, options.data_transport_options,
   1731                          current_description, desc)) {
   1732     return false;
   1733   }
   1734   return true;
   1735 }
   1736 
   1737 bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
   1738     const SessionDescription* offer,
   1739     const MediaSessionOptions& options,
   1740     const SessionDescription* current_description,
   1741     StreamParamsVec* current_streams,
   1742     SessionDescription* answer) const {
   1743   const ContentInfo* audio_content = GetFirstAudioContent(offer);
   1744 
   1745   scoped_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
   1746       audio_content->name, offer, options.audio_transport_options,
   1747       current_description));
   1748   if (!audio_transport) {
   1749     return false;
   1750   }
   1751 
   1752   AudioCodecs audio_codecs = audio_codecs_;
   1753   if (!options.vad_enabled) {
   1754     StripCNCodecs(&audio_codecs);
   1755   }
   1756 
   1757   bool bundle_enabled =
   1758       offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
   1759   scoped_ptr<AudioContentDescription> audio_answer(
   1760       new AudioContentDescription());
   1761   // Do not require or create SDES cryptos if DTLS is used.
   1762   cricket::SecurePolicy sdes_policy =
   1763       audio_transport->secure() ? cricket::SEC_DISABLED : secure();
   1764   if (!CreateMediaContentAnswer(
   1765           static_cast<const AudioContentDescription*>(
   1766               audio_content->description),
   1767           options,
   1768           audio_codecs,
   1769           sdes_policy,
   1770           GetCryptos(GetFirstAudioContentDescription(current_description)),
   1771           audio_rtp_extensions_,
   1772           current_streams,
   1773           add_legacy_,
   1774           bundle_enabled,
   1775           audio_answer.get())) {
   1776     return false;  // Fails the session setup.
   1777   }
   1778 
   1779   bool rejected = !options.has_audio() || audio_content->rejected ||
   1780       !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
   1781                                 audio_answer->protocol(),
   1782                                 audio_transport->secure());
   1783   if (!rejected) {
   1784     AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer);
   1785   } else {
   1786     // RFC 3264
   1787     // The answer MUST contain the same number of m-lines as the offer.
   1788     LOG(LS_INFO) << "Audio is not supported in the answer.";
   1789   }
   1790 
   1791   answer->AddContent(audio_content->name, audio_content->type, rejected,
   1792                      audio_answer.release());
   1793   return true;
   1794 }
   1795 
   1796 bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
   1797     const SessionDescription* offer,
   1798     const MediaSessionOptions& options,
   1799     const SessionDescription* current_description,
   1800     StreamParamsVec* current_streams,
   1801     SessionDescription* answer) const {
   1802   const ContentInfo* video_content = GetFirstVideoContent(offer);
   1803   scoped_ptr<TransportDescription> video_transport(CreateTransportAnswer(
   1804       video_content->name, offer, options.video_transport_options,
   1805       current_description));
   1806   if (!video_transport) {
   1807     return false;
   1808   }
   1809 
   1810   scoped_ptr<VideoContentDescription> video_answer(
   1811       new VideoContentDescription());
   1812   // Do not require or create SDES cryptos if DTLS is used.
   1813   cricket::SecurePolicy sdes_policy =
   1814       video_transport->secure() ? cricket::SEC_DISABLED : secure();
   1815   bool bundle_enabled =
   1816       offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
   1817   if (!CreateMediaContentAnswer(
   1818           static_cast<const VideoContentDescription*>(
   1819               video_content->description),
   1820           options,
   1821           video_codecs_,
   1822           sdes_policy,
   1823           GetCryptos(GetFirstVideoContentDescription(current_description)),
   1824           video_rtp_extensions_,
   1825           current_streams,
   1826           add_legacy_,
   1827           bundle_enabled,
   1828           video_answer.get())) {
   1829     return false;
   1830   }
   1831   bool rejected = !options.has_video() || video_content->rejected ||
   1832       !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
   1833                                 video_answer->protocol(),
   1834                                 video_transport->secure());
   1835   if (!rejected) {
   1836     if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
   1837                             answer)) {
   1838       return false;
   1839     }
   1840     video_answer->set_bandwidth(options.video_bandwidth);
   1841   } else {
   1842     // RFC 3264
   1843     // The answer MUST contain the same number of m-lines as the offer.
   1844     LOG(LS_INFO) << "Video is not supported in the answer.";
   1845   }
   1846   answer->AddContent(video_content->name, video_content->type, rejected,
   1847                      video_answer.release());
   1848   return true;
   1849 }
   1850 
   1851 bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
   1852     const SessionDescription* offer,
   1853     const MediaSessionOptions& options,
   1854     const SessionDescription* current_description,
   1855     StreamParamsVec* current_streams,
   1856     SessionDescription* answer) const {
   1857   const ContentInfo* data_content = GetFirstDataContent(offer);
   1858   scoped_ptr<TransportDescription> data_transport(CreateTransportAnswer(
   1859       data_content->name, offer, options.data_transport_options,
   1860       current_description));
   1861   if (!data_transport) {
   1862     return false;
   1863   }
   1864   bool is_sctp = (options.data_channel_type == DCT_SCTP);
   1865   std::vector<DataCodec> data_codecs(data_codecs_);
   1866   FilterDataCodecs(&data_codecs, is_sctp);
   1867 
   1868   scoped_ptr<DataContentDescription> data_answer(
   1869       new DataContentDescription());
   1870   // Do not require or create SDES cryptos if DTLS is used.
   1871   cricket::SecurePolicy sdes_policy =
   1872       data_transport->secure() ? cricket::SEC_DISABLED : secure();
   1873   bool bundle_enabled =
   1874       offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
   1875   if (!CreateMediaContentAnswer(
   1876           static_cast<const DataContentDescription*>(
   1877               data_content->description),
   1878           options,
   1879           data_codecs_,
   1880           sdes_policy,
   1881           GetCryptos(GetFirstDataContentDescription(current_description)),
   1882           RtpHeaderExtensions(),
   1883           current_streams,
   1884           add_legacy_,
   1885           bundle_enabled,
   1886           data_answer.get())) {
   1887     return false;  // Fails the session setup.
   1888   }
   1889 
   1890   bool rejected = !options.has_data() || data_content->rejected ||
   1891       !IsMediaProtocolSupported(MEDIA_TYPE_DATA,
   1892                                 data_answer->protocol(),
   1893                                 data_transport->secure());
   1894   if (!rejected) {
   1895     data_answer->set_bandwidth(options.data_bandwidth);
   1896     if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
   1897                             answer)) {
   1898       return false;
   1899     }
   1900   } else {
   1901     // RFC 3264
   1902     // The answer MUST contain the same number of m-lines as the offer.
   1903     LOG(LS_INFO) << "Data is not supported in the answer.";
   1904   }
   1905   answer->AddContent(data_content->name, data_content->type, rejected,
   1906                      data_answer.release());
   1907   return true;
   1908 }
   1909 
   1910 bool IsMediaContent(const ContentInfo* content) {
   1911   return (content &&
   1912           (content->type == NS_JINGLE_RTP ||
   1913            content->type == NS_JINGLE_DRAFT_SCTP));
   1914 }
   1915 
   1916 bool IsAudioContent(const ContentInfo* content) {
   1917   return IsMediaContentOfType(content, MEDIA_TYPE_AUDIO);
   1918 }
   1919 
   1920 bool IsVideoContent(const ContentInfo* content) {
   1921   return IsMediaContentOfType(content, MEDIA_TYPE_VIDEO);
   1922 }
   1923 
   1924 bool IsDataContent(const ContentInfo* content) {
   1925   return IsMediaContentOfType(content, MEDIA_TYPE_DATA);
   1926 }
   1927 
   1928 static const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
   1929                                                MediaType media_type) {
   1930   for (ContentInfos::const_iterator content = contents.begin();
   1931        content != contents.end(); content++) {
   1932     if (IsMediaContentOfType(&*content, media_type)) {
   1933       return &*content;
   1934     }
   1935   }
   1936   return NULL;
   1937 }
   1938 
   1939 const ContentInfo* GetFirstAudioContent(const ContentInfos& contents) {
   1940   return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
   1941 }
   1942 
   1943 const ContentInfo* GetFirstVideoContent(const ContentInfos& contents) {
   1944   return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
   1945 }
   1946 
   1947 const ContentInfo* GetFirstDataContent(const ContentInfos& contents) {
   1948   return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
   1949 }
   1950 
   1951 static const ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
   1952                                                MediaType media_type) {
   1953   if (sdesc == NULL)
   1954     return NULL;
   1955 
   1956   return GetFirstMediaContent(sdesc->contents(), media_type);
   1957 }
   1958 
   1959 const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
   1960   return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
   1961 }
   1962 
   1963 const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
   1964   return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
   1965 }
   1966 
   1967 const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc) {
   1968   return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
   1969 }
   1970 
   1971 const MediaContentDescription* GetFirstMediaContentDescription(
   1972     const SessionDescription* sdesc, MediaType media_type) {
   1973   const ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
   1974   const ContentDescription* description = content ? content->description : NULL;
   1975   return static_cast<const MediaContentDescription*>(description);
   1976 }
   1977 
   1978 const AudioContentDescription* GetFirstAudioContentDescription(
   1979     const SessionDescription* sdesc) {
   1980   return static_cast<const AudioContentDescription*>(
   1981       GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
   1982 }
   1983 
   1984 const VideoContentDescription* GetFirstVideoContentDescription(
   1985     const SessionDescription* sdesc) {
   1986   return static_cast<const VideoContentDescription*>(
   1987       GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
   1988 }
   1989 
   1990 const DataContentDescription* GetFirstDataContentDescription(
   1991     const SessionDescription* sdesc) {
   1992   return static_cast<const DataContentDescription*>(
   1993       GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
   1994 }
   1995 
   1996 }  // namespace cricket
   1997