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