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