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