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