Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2011 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/app/webrtc/webrtcsdp.h"
     29 
     30 #include <limits.h>
     31 #include <stdio.h>
     32 #include <algorithm>
     33 #include <string>
     34 #include <vector>
     35 #include <ctype.h>
     36 
     37 #include "talk/app/webrtc/jsepicecandidate.h"
     38 #include "talk/app/webrtc/jsepsessiondescription.h"
     39 #include "talk/media/base/codec.h"
     40 #include "talk/media/base/constants.h"
     41 #include "talk/media/base/cryptoparams.h"
     42 #include "talk/media/base/rtputils.h"
     43 #include "talk/media/sctp/sctpdataengine.h"
     44 #include "webrtc/p2p/base/candidate.h"
     45 #include "webrtc/p2p/base/constants.h"
     46 #include "webrtc/p2p/base/port.h"
     47 #include "talk/session/media/mediasession.h"
     48 #include "webrtc/base/arraysize.h"
     49 #include "webrtc/base/common.h"
     50 #include "webrtc/base/logging.h"
     51 #include "webrtc/base/messagedigest.h"
     52 #include "webrtc/base/stringutils.h"
     53 
     54 using cricket::AudioContentDescription;
     55 using cricket::Candidate;
     56 using cricket::Candidates;
     57 using cricket::ContentDescription;
     58 using cricket::ContentInfo;
     59 using cricket::CryptoParams;
     60 using cricket::DataContentDescription;
     61 using cricket::ICE_CANDIDATE_COMPONENT_RTP;
     62 using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
     63 using cricket::kCodecParamMaxBitrate;
     64 using cricket::kCodecParamMaxPTime;
     65 using cricket::kCodecParamMaxQuantization;
     66 using cricket::kCodecParamMinBitrate;
     67 using cricket::kCodecParamMinPTime;
     68 using cricket::kCodecParamPTime;
     69 using cricket::kCodecParamSPropStereo;
     70 using cricket::kCodecParamStartBitrate;
     71 using cricket::kCodecParamStereo;
     72 using cricket::kCodecParamUseInbandFec;
     73 using cricket::kCodecParamUseDtx;
     74 using cricket::kCodecParamSctpProtocol;
     75 using cricket::kCodecParamSctpStreams;
     76 using cricket::kCodecParamMaxAverageBitrate;
     77 using cricket::kCodecParamMaxPlaybackRate;
     78 using cricket::kCodecParamAssociatedPayloadType;
     79 using cricket::MediaContentDescription;
     80 using cricket::MediaType;
     81 using cricket::RtpHeaderExtension;
     82 using cricket::SsrcGroup;
     83 using cricket::StreamParams;
     84 using cricket::StreamParamsVec;
     85 using cricket::TransportDescription;
     86 using cricket::TransportInfo;
     87 using cricket::VideoContentDescription;
     88 using rtc::SocketAddress;
     89 
     90 typedef std::vector<RtpHeaderExtension> RtpHeaderExtensions;
     91 
     92 namespace cricket {
     93 class SessionDescription;
     94 }
     95 
     96 namespace webrtc {
     97 
     98 // Line type
     99 // RFC 4566
    100 // An SDP session description consists of a number of lines of text of
    101 // the form:
    102 // <type>=<value>
    103 // where <type> MUST be exactly one case-significant character.
    104 static const int kLinePrefixLength = 2;  // Lenght of <type>=
    105 static const char kLineTypeVersion = 'v';
    106 static const char kLineTypeOrigin = 'o';
    107 static const char kLineTypeSessionName = 's';
    108 static const char kLineTypeSessionInfo = 'i';
    109 static const char kLineTypeSessionUri = 'u';
    110 static const char kLineTypeSessionEmail = 'e';
    111 static const char kLineTypeSessionPhone = 'p';
    112 static const char kLineTypeSessionBandwidth = 'b';
    113 static const char kLineTypeTiming = 't';
    114 static const char kLineTypeRepeatTimes = 'r';
    115 static const char kLineTypeTimeZone = 'z';
    116 static const char kLineTypeEncryptionKey = 'k';
    117 static const char kLineTypeMedia = 'm';
    118 static const char kLineTypeConnection = 'c';
    119 static const char kLineTypeAttributes = 'a';
    120 
    121 // Attributes
    122 static const char kAttributeGroup[] = "group";
    123 static const char kAttributeMid[] = "mid";
    124 static const char kAttributeRtcpMux[] = "rtcp-mux";
    125 static const char kAttributeRtcpReducedSize[] = "rtcp-rsize";
    126 static const char kAttributeSsrc[] = "ssrc";
    127 static const char kSsrcAttributeCname[] = "cname";
    128 static const char kAttributeExtmap[] = "extmap";
    129 // draft-alvestrand-mmusic-msid-01
    130 // a=msid-semantic: WMS
    131 static const char kAttributeMsidSemantics[] = "msid-semantic";
    132 static const char kMediaStreamSemantic[] = "WMS";
    133 static const char kSsrcAttributeMsid[] = "msid";
    134 static const char kDefaultMsid[] = "default";
    135 static const char kSsrcAttributeMslabel[] = "mslabel";
    136 static const char kSSrcAttributeLabel[] = "label";
    137 static const char kAttributeSsrcGroup[] = "ssrc-group";
    138 static const char kAttributeCrypto[] = "crypto";
    139 static const char kAttributeCandidate[] = "candidate";
    140 static const char kAttributeCandidateTyp[] = "typ";
    141 static const char kAttributeCandidateRaddr[] = "raddr";
    142 static const char kAttributeCandidateRport[] = "rport";
    143 static const char kAttributeCandidateUfrag[] = "ufrag";
    144 static const char kAttributeCandidatePwd[] = "pwd";
    145 static const char kAttributeCandidateGeneration[] = "generation";
    146 static const char kAttributeFingerprint[] = "fingerprint";
    147 static const char kAttributeSetup[] = "setup";
    148 static const char kAttributeFmtp[] = "fmtp";
    149 static const char kAttributeRtpmap[] = "rtpmap";
    150 static const char kAttributeSctpmap[] = "sctpmap";
    151 static const char kAttributeRtcp[] = "rtcp";
    152 static const char kAttributeIceUfrag[] = "ice-ufrag";
    153 static const char kAttributeIcePwd[] = "ice-pwd";
    154 static const char kAttributeIceLite[] = "ice-lite";
    155 static const char kAttributeIceOption[] = "ice-options";
    156 static const char kAttributeSendOnly[] = "sendonly";
    157 static const char kAttributeRecvOnly[] = "recvonly";
    158 static const char kAttributeRtcpFb[] = "rtcp-fb";
    159 static const char kAttributeSendRecv[] = "sendrecv";
    160 static const char kAttributeInactive[] = "inactive";
    161 // draft-ietf-mmusic-sctp-sdp-07
    162 // a=sctp-port
    163 static const char kAttributeSctpPort[] = "sctp-port";
    164 
    165 // Experimental flags
    166 static const char kAttributeXGoogleFlag[] = "x-google-flag";
    167 static const char kValueConference[] = "conference";
    168 
    169 // Candidate
    170 static const char kCandidateHost[] = "host";
    171 static const char kCandidateSrflx[] = "srflx";
    172 // TODO: How to map the prflx with circket candidate type
    173 // static const char kCandidatePrflx[] = "prflx";
    174 static const char kCandidateRelay[] = "relay";
    175 static const char kTcpCandidateType[] = "tcptype";
    176 
    177 static const char kSdpDelimiterEqual = '=';
    178 static const char kSdpDelimiterSpace = ' ';
    179 static const char kSdpDelimiterColon = ':';
    180 static const char kSdpDelimiterSemicolon = ';';
    181 static const char kSdpDelimiterSlash = '/';
    182 static const char kNewLine = '\n';
    183 static const char kReturn = '\r';
    184 static const char kLineBreak[] = "\r\n";
    185 
    186 // TODO: Generate the Session and Time description
    187 // instead of hardcoding.
    188 static const char kSessionVersion[] = "v=0";
    189 // RFC 4566
    190 static const char kSessionOriginUsername[] = "-";
    191 static const char kSessionOriginSessionId[] = "0";
    192 static const char kSessionOriginSessionVersion[] = "0";
    193 static const char kSessionOriginNettype[] = "IN";
    194 static const char kSessionOriginAddrtype[] = "IP4";
    195 static const char kSessionOriginAddress[] = "127.0.0.1";
    196 static const char kSessionName[] = "s=-";
    197 static const char kTimeDescription[] = "t=0 0";
    198 static const char kAttrGroup[] = "a=group:BUNDLE";
    199 static const char kConnectionNettype[] = "IN";
    200 static const char kConnectionIpv4Addrtype[] = "IP4";
    201 static const char kConnectionIpv6Addrtype[] = "IP6";
    202 static const char kMediaTypeVideo[] = "video";
    203 static const char kMediaTypeAudio[] = "audio";
    204 static const char kMediaTypeData[] = "application";
    205 static const char kMediaPortRejected[] = "0";
    206 // draft-ietf-mmusic-trickle-ice-01
    207 // When no candidates have been gathered, set the connection
    208 // address to IP6 ::.
    209 // TODO(perkj): FF can not parse IP6 ::. See http://crbug/430333
    210 // Use IPV4 per default.
    211 static const char kDummyAddress[] = "0.0.0.0";
    212 static const char kDummyPort[] = "9";
    213 // RFC 3556
    214 static const char kApplicationSpecificMaximum[] = "AS";
    215 
    216 static const int kDefaultVideoClockrate = 90000;
    217 
    218 // ISAC special-case.
    219 static const char kIsacCodecName[] = "ISAC";  // From webrtcvoiceengine.cc
    220 static const int kIsacWbDefaultRate = 32000;  // From acm_common_defs.h
    221 static const int kIsacSwbDefaultRate = 56000;  // From acm_common_defs.h
    222 
    223 static const char kDefaultSctpmapProtocol[] = "webrtc-datachannel";
    224 
    225 // RTP payload type is in the 0-127 range. Use -1 to indicate "all" payload
    226 // types.
    227 const int kWildcardPayloadType = -1;
    228 
    229 struct SsrcInfo {
    230   SsrcInfo()
    231       : msid_identifier(kDefaultMsid),
    232         // TODO(ronghuawu): What should we do if the appdata doesn't appear?
    233         // Create random string (which will be used as track label later)?
    234         msid_appdata(rtc::CreateRandomString(8)) {
    235   }
    236   uint32_t ssrc_id;
    237   std::string cname;
    238   std::string msid_identifier;
    239   std::string msid_appdata;
    240 
    241   // For backward compatibility.
    242   // TODO(ronghuawu): Remove below 2 fields once all the clients support msid.
    243   std::string label;
    244   std::string mslabel;
    245 };
    246 typedef std::vector<SsrcInfo> SsrcInfoVec;
    247 typedef std::vector<SsrcGroup> SsrcGroupVec;
    248 
    249 template <class T>
    250 static void AddFmtpLine(const T& codec, std::string* message);
    251 static void BuildMediaDescription(const ContentInfo* content_info,
    252                                   const TransportInfo* transport_info,
    253                                   const MediaType media_type,
    254                                   const std::vector<Candidate>& candidates,
    255                                   std::string* message);
    256 static void BuildSctpContentAttributes(std::string* message, int sctp_port);
    257 static void BuildRtpContentAttributes(
    258     const MediaContentDescription* media_desc,
    259     const MediaType media_type,
    260     std::string* message);
    261 static void BuildRtpMap(const MediaContentDescription* media_desc,
    262                         const MediaType media_type,
    263                         std::string* message);
    264 static void BuildCandidate(const std::vector<Candidate>& candidates,
    265                            bool include_ufrag,
    266                            std::string* message);
    267 static void BuildIceOptions(const std::vector<std::string>& transport_options,
    268                             std::string* message);
    269 static bool IsRtp(const std::string& protocol);
    270 static bool IsDtlsSctp(const std::string& protocol);
    271 static bool ParseSessionDescription(const std::string& message, size_t* pos,
    272                                     std::string* session_id,
    273                                     std::string* session_version,
    274                                     TransportDescription* session_td,
    275                                     RtpHeaderExtensions* session_extmaps,
    276                                     cricket::SessionDescription* desc,
    277                                     SdpParseError* error);
    278 static bool ParseGroupAttribute(const std::string& line,
    279                                 cricket::SessionDescription* desc,
    280                                 SdpParseError* error);
    281 static bool ParseMediaDescription(
    282     const std::string& message,
    283     const TransportDescription& session_td,
    284     const RtpHeaderExtensions& session_extmaps,
    285     size_t* pos, cricket::SessionDescription* desc,
    286     std::vector<JsepIceCandidate*>* candidates,
    287     SdpParseError* error);
    288 static bool ParseContent(const std::string& message,
    289                          const MediaType media_type,
    290                          int mline_index,
    291                          const std::string& protocol,
    292                          const std::vector<int>& codec_preference,
    293                          size_t* pos,
    294                          std::string* content_name,
    295                          MediaContentDescription* media_desc,
    296                          TransportDescription* transport,
    297                          std::vector<JsepIceCandidate*>* candidates,
    298                          SdpParseError* error);
    299 static bool ParseSsrcAttribute(const std::string& line,
    300                                SsrcInfoVec* ssrc_infos,
    301                                SdpParseError* error);
    302 static bool ParseSsrcGroupAttribute(const std::string& line,
    303                                     SsrcGroupVec* ssrc_groups,
    304                                     SdpParseError* error);
    305 static bool ParseCryptoAttribute(const std::string& line,
    306                                  MediaContentDescription* media_desc,
    307                                  SdpParseError* error);
    308 static bool ParseRtpmapAttribute(const std::string& line,
    309                                  const MediaType media_type,
    310                                  const std::vector<int>& codec_preference,
    311                                  MediaContentDescription* media_desc,
    312                                  SdpParseError* error);
    313 static bool ParseFmtpAttributes(const std::string& line,
    314                                 const MediaType media_type,
    315                                 MediaContentDescription* media_desc,
    316                                 SdpParseError* error);
    317 static bool ParseFmtpParam(const std::string& line, std::string* parameter,
    318                            std::string* value, SdpParseError* error);
    319 static bool ParseCandidate(const std::string& message, Candidate* candidate,
    320                            SdpParseError* error, bool is_raw);
    321 static bool ParseRtcpFbAttribute(const std::string& line,
    322                                  const MediaType media_type,
    323                                  MediaContentDescription* media_desc,
    324                                  SdpParseError* error);
    325 static bool ParseIceOptions(const std::string& line,
    326                             std::vector<std::string>* transport_options,
    327                             SdpParseError* error);
    328 static bool ParseExtmap(const std::string& line,
    329                         RtpHeaderExtension* extmap,
    330                         SdpParseError* error);
    331 static bool ParseFingerprintAttribute(const std::string& line,
    332                                       rtc::SSLFingerprint** fingerprint,
    333                                       SdpParseError* error);
    334 static bool ParseDtlsSetup(const std::string& line,
    335                            cricket::ConnectionRole* role,
    336                            SdpParseError* error);
    337 
    338 // Helper functions
    339 
    340 // Below ParseFailed*** functions output the line that caused the parsing
    341 // failure and the detailed reason (|description|) of the failure to |error|.
    342 // The functions always return false so that they can be used directly in the
    343 // following way when error happens:
    344 // "return ParseFailed***(...);"
    345 
    346 // The line starting at |line_start| of |message| is the failing line.
    347 // The reason for the failure should be provided in the |description|.
    348 // An example of a description could be "unknown character".
    349 static bool ParseFailed(const std::string& message,
    350                         size_t line_start,
    351                         const std::string& description,
    352                         SdpParseError* error) {
    353   // Get the first line of |message| from |line_start|.
    354   std::string first_line;
    355   size_t line_end = message.find(kNewLine, line_start);
    356   if (line_end != std::string::npos) {
    357     if (line_end > 0 && (message.at(line_end - 1) == kReturn)) {
    358       --line_end;
    359     }
    360     first_line = message.substr(line_start, (line_end - line_start));
    361   } else {
    362     first_line = message.substr(line_start);
    363   }
    364 
    365   if (error) {
    366     error->line = first_line;
    367     error->description = description;
    368   }
    369   LOG(LS_ERROR) << "Failed to parse: \"" << first_line
    370                 << "\". Reason: " << description;
    371   return false;
    372 }
    373 
    374 // |line| is the failing line. The reason for the failure should be
    375 // provided in the |description|.
    376 static bool ParseFailed(const std::string& line,
    377                         const std::string& description,
    378                         SdpParseError* error) {
    379   return ParseFailed(line, 0, description, error);
    380 }
    381 
    382 // Parses failure where the failing SDP line isn't know or there are multiple
    383 // failing lines.
    384 static bool ParseFailed(const std::string& description,
    385                         SdpParseError* error) {
    386   return ParseFailed("", description, error);
    387 }
    388 
    389 // |line| is the failing line. The failure is due to the fact that |line|
    390 // doesn't have |expected_fields| fields.
    391 static bool ParseFailedExpectFieldNum(const std::string& line,
    392                                       int expected_fields,
    393                                       SdpParseError* error) {
    394   std::ostringstream description;
    395   description << "Expects " << expected_fields << " fields.";
    396   return ParseFailed(line, description.str(), error);
    397 }
    398 
    399 // |line| is the failing line. The failure is due to the fact that |line| has
    400 // less than |expected_min_fields| fields.
    401 static bool ParseFailedExpectMinFieldNum(const std::string& line,
    402                                          int expected_min_fields,
    403                                          SdpParseError* error) {
    404   std::ostringstream description;
    405   description << "Expects at least " << expected_min_fields << " fields.";
    406   return ParseFailed(line, description.str(), error);
    407 }
    408 
    409 // |line| is the failing line. The failure is due to the fact that it failed to
    410 // get the value of |attribute|.
    411 static bool ParseFailedGetValue(const std::string& line,
    412                                 const std::string& attribute,
    413                                 SdpParseError* error) {
    414   std::ostringstream description;
    415   description << "Failed to get the value of attribute: " << attribute;
    416   return ParseFailed(line, description.str(), error);
    417 }
    418 
    419 // The line starting at |line_start| of |message| is the failing line. The
    420 // failure is due to the line type (e.g. the "m" part of the "m-line")
    421 // not matching what is expected. The expected line type should be
    422 // provided as |line_type|.
    423 static bool ParseFailedExpectLine(const std::string& message,
    424                                   size_t line_start,
    425                                   const char line_type,
    426                                   const std::string& line_value,
    427                                   SdpParseError* error) {
    428   std::ostringstream description;
    429   description << "Expect line: " << line_type << "=" << line_value;
    430   return ParseFailed(message, line_start, description.str(), error);
    431 }
    432 
    433 static bool AddLine(const std::string& line, std::string* message) {
    434   if (!message)
    435     return false;
    436 
    437   message->append(line);
    438   message->append(kLineBreak);
    439   return true;
    440 }
    441 
    442 static bool GetLine(const std::string& message,
    443                     size_t* pos,
    444                     std::string* line) {
    445   size_t line_begin = *pos;
    446   size_t line_end = message.find(kNewLine, line_begin);
    447   if (line_end == std::string::npos) {
    448     return false;
    449   }
    450   // Update the new start position
    451   *pos = line_end + 1;
    452   if (line_end > 0 && (message.at(line_end - 1) == kReturn)) {
    453     --line_end;
    454   }
    455   *line = message.substr(line_begin, (line_end - line_begin));
    456   const char* cline = line->c_str();
    457   // RFC 4566
    458   // An SDP session description consists of a number of lines of text of
    459   // the form:
    460   // <type>=<value>
    461   // where <type> MUST be exactly one case-significant character and
    462   // <value> is structured text whose format depends on <type>.
    463   // Whitespace MUST NOT be used on either side of the "=" sign.
    464   if (line->length() < 3 ||
    465       !islower(cline[0]) ||
    466       cline[1] != kSdpDelimiterEqual ||
    467       cline[2] == kSdpDelimiterSpace) {
    468     *pos = line_begin;
    469     return false;
    470   }
    471   return true;
    472 }
    473 
    474 // Init |os| to "|type|=|value|".
    475 static void InitLine(const char type,
    476                      const std::string& value,
    477                      std::ostringstream* os) {
    478   os->str("");
    479   *os << type << kSdpDelimiterEqual << value;
    480 }
    481 
    482 // Init |os| to "a=|attribute|".
    483 static void InitAttrLine(const std::string& attribute, std::ostringstream* os) {
    484   InitLine(kLineTypeAttributes, attribute, os);
    485 }
    486 
    487 // Writes a SDP attribute line based on |attribute| and |value| to |message|.
    488 static void AddAttributeLine(const std::string& attribute, int value,
    489                              std::string* message) {
    490   std::ostringstream os;
    491   InitAttrLine(attribute, &os);
    492   os << kSdpDelimiterColon << value;
    493   AddLine(os.str(), message);
    494 }
    495 
    496 static bool IsLineType(const std::string& message,
    497                        const char type,
    498                        size_t line_start) {
    499   if (message.size() < line_start + kLinePrefixLength) {
    500     return false;
    501   }
    502   const char* cmessage = message.c_str();
    503   return (cmessage[line_start] == type &&
    504           cmessage[line_start + 1] == kSdpDelimiterEqual);
    505 }
    506 
    507 static bool IsLineType(const std::string& line,
    508                        const char type) {
    509   return IsLineType(line, type, 0);
    510 }
    511 
    512 static bool GetLineWithType(const std::string& message, size_t* pos,
    513                             std::string* line, const char type) {
    514   if (!IsLineType(message, type, *pos)) {
    515     return false;
    516   }
    517 
    518   if (!GetLine(message, pos, line))
    519     return false;
    520 
    521   return true;
    522 }
    523 
    524 static bool HasAttribute(const std::string& line,
    525                          const std::string& attribute) {
    526   return (line.compare(kLinePrefixLength, attribute.size(), attribute) == 0);
    527 }
    528 
    529 static bool AddSsrcLine(uint32_t ssrc_id,
    530                         const std::string& attribute,
    531                         const std::string& value,
    532                         std::string* message) {
    533   // RFC 5576
    534   // a=ssrc:<ssrc-id> <attribute>:<value>
    535   std::ostringstream os;
    536   InitAttrLine(kAttributeSsrc, &os);
    537   os << kSdpDelimiterColon << ssrc_id << kSdpDelimiterSpace
    538      << attribute << kSdpDelimiterColon << value;
    539   return AddLine(os.str(), message);
    540 }
    541 
    542 // Get value only from <attribute>:<value>.
    543 static bool GetValue(const std::string& message, const std::string& attribute,
    544                      std::string* value, SdpParseError* error) {
    545   std::string leftpart;
    546   if (!rtc::tokenize_first(message, kSdpDelimiterColon, &leftpart, value)) {
    547     return ParseFailedGetValue(message, attribute, error);
    548   }
    549   // The left part should end with the expected attribute.
    550   if (leftpart.length() < attribute.length() ||
    551       leftpart.compare(leftpart.length() - attribute.length(),
    552                        attribute.length(), attribute) != 0) {
    553     return ParseFailedGetValue(message, attribute, error);
    554   }
    555   return true;
    556 }
    557 
    558 static bool CaseInsensitiveFind(std::string str1, std::string str2) {
    559   std::transform(str1.begin(), str1.end(), str1.begin(),
    560                  ::tolower);
    561   std::transform(str2.begin(), str2.end(), str2.begin(),
    562                  ::tolower);
    563   return str1.find(str2) != std::string::npos;
    564 }
    565 
    566 template <class T>
    567 static bool GetValueFromString(const std::string& line,
    568                                const std::string& s,
    569                                T* t,
    570                                SdpParseError* error) {
    571   if (!rtc::FromString(s, t)) {
    572     std::ostringstream description;
    573     description << "Invalid value: " << s << ".";
    574     return ParseFailed(line, description.str(), error);
    575   }
    576   return true;
    577 }
    578 
    579 static bool GetPayloadTypeFromString(const std::string& line,
    580                                      const std::string& s,
    581                                      int* payload_type,
    582                                      SdpParseError* error) {
    583   return GetValueFromString(line, s, payload_type, error) &&
    584       cricket::IsValidRtpPayloadType(*payload_type);
    585 }
    586 
    587 void CreateTracksFromSsrcInfos(const SsrcInfoVec& ssrc_infos,
    588                                StreamParamsVec* tracks) {
    589   ASSERT(tracks != NULL);
    590   for (SsrcInfoVec::const_iterator ssrc_info = ssrc_infos.begin();
    591        ssrc_info != ssrc_infos.end(); ++ssrc_info) {
    592     if (ssrc_info->cname.empty()) {
    593       continue;
    594     }
    595 
    596     std::string sync_label;
    597     std::string track_id;
    598     if (ssrc_info->msid_identifier == kDefaultMsid &&
    599         !ssrc_info->mslabel.empty()) {
    600       // If there's no msid and there's mslabel, we consider this is a sdp from
    601       // a older version of client that doesn't support msid.
    602       // In that case, we use the mslabel and label to construct the track.
    603       sync_label = ssrc_info->mslabel;
    604       track_id = ssrc_info->label;
    605     } else {
    606       sync_label = ssrc_info->msid_identifier;
    607       // The appdata consists of the "id" attribute of a MediaStreamTrack, which
    608       // is corresponding to the "id" attribute of StreamParams.
    609       track_id = ssrc_info->msid_appdata;
    610     }
    611     if (sync_label.empty() || track_id.empty()) {
    612       ASSERT(false);
    613       continue;
    614     }
    615 
    616     StreamParamsVec::iterator track = tracks->begin();
    617     for (; track != tracks->end(); ++track) {
    618       if (track->id == track_id) {
    619         break;
    620       }
    621     }
    622     if (track == tracks->end()) {
    623       // If we don't find an existing track, create a new one.
    624       tracks->push_back(StreamParams());
    625       track = tracks->end() - 1;
    626     }
    627     track->add_ssrc(ssrc_info->ssrc_id);
    628     track->cname = ssrc_info->cname;
    629     track->sync_label = sync_label;
    630     track->id = track_id;
    631   }
    632 }
    633 
    634 void GetMediaStreamLabels(const ContentInfo* content,
    635                           std::set<std::string>* labels) {
    636   const MediaContentDescription* media_desc =
    637       static_cast<const MediaContentDescription*>(
    638           content->description);
    639   const cricket::StreamParamsVec& streams =  media_desc->streams();
    640   for (cricket::StreamParamsVec::const_iterator it = streams.begin();
    641        it != streams.end(); ++it) {
    642     labels->insert(it->sync_label);
    643   }
    644 }
    645 
    646 // RFC 5245
    647 // It is RECOMMENDED that default candidates be chosen based on the
    648 // likelihood of those candidates to work with the peer that is being
    649 // contacted.  It is RECOMMENDED that relayed > reflexive > host.
    650 static const int kPreferenceUnknown = 0;
    651 static const int kPreferenceHost = 1;
    652 static const int kPreferenceReflexive = 2;
    653 static const int kPreferenceRelayed = 3;
    654 
    655 static int GetCandidatePreferenceFromType(const std::string& type) {
    656   int preference = kPreferenceUnknown;
    657   if (type == cricket::LOCAL_PORT_TYPE) {
    658     preference = kPreferenceHost;
    659   } else if (type == cricket::STUN_PORT_TYPE) {
    660     preference = kPreferenceReflexive;
    661   } else if (type == cricket::RELAY_PORT_TYPE) {
    662     preference = kPreferenceRelayed;
    663   } else {
    664     ASSERT(false);
    665   }
    666   return preference;
    667 }
    668 
    669 // Get ip and port of the default destination from the |candidates| with the
    670 // given value of |component_id|. The default candidate should be the one most
    671 // likely to work, typically IPv4 relay.
    672 // RFC 5245
    673 // The value of |component_id| currently supported are 1 (RTP) and 2 (RTCP).
    674 // TODO: Decide the default destination in webrtcsession and
    675 // pass it down via SessionDescription.
    676 static void GetDefaultDestination(
    677     const std::vector<Candidate>& candidates,
    678     int component_id, std::string* port,
    679     std::string* ip, std::string* addr_type) {
    680   *addr_type = kConnectionIpv4Addrtype;
    681   *port = kDummyPort;
    682   *ip = kDummyAddress;
    683   int current_preference = kPreferenceUnknown;
    684   int current_family = AF_UNSPEC;
    685   for (std::vector<Candidate>::const_iterator it = candidates.begin();
    686        it != candidates.end(); ++it) {
    687     if (it->component() != component_id) {
    688       continue;
    689     }
    690     // Default destination should be UDP only.
    691     if (it->protocol() != cricket::UDP_PROTOCOL_NAME) {
    692       continue;
    693     }
    694     const int preference = GetCandidatePreferenceFromType(it->type());
    695     const int family = it->address().ipaddr().family();
    696     // See if this candidate is more preferable then the current one if it's the
    697     // same family. Or if the current family is IPv4 already so we could safely
    698     // ignore all IPv6 ones. WebRTC bug 4269.
    699     // http://code.google.com/p/webrtc/issues/detail?id=4269
    700     if ((preference <= current_preference && current_family == family) ||
    701         (current_family == AF_INET && family == AF_INET6)) {
    702       continue;
    703     }
    704     if (family == AF_INET) {
    705       addr_type->assign(kConnectionIpv4Addrtype);
    706     } else if (family == AF_INET6) {
    707       addr_type->assign(kConnectionIpv6Addrtype);
    708     }
    709     current_preference = preference;
    710     current_family = family;
    711     *port = it->address().PortAsString();
    712     *ip = it->address().ipaddr().ToString();
    713   }
    714 }
    715 
    716 // Update |mline|'s default destination and append a c line after it.
    717 static void UpdateMediaDefaultDestination(
    718     const std::vector<Candidate>& candidates,
    719     const std::string& mline,
    720     std::string* message) {
    721   std::string new_lines;
    722   AddLine(mline, &new_lines);
    723   // RFC 4566
    724   // m=<media> <port> <proto> <fmt> ...
    725   std::vector<std::string> fields;
    726   rtc::split(mline, kSdpDelimiterSpace, &fields);
    727   if (fields.size() < 3) {
    728     return;
    729   }
    730 
    731   std::ostringstream os;
    732   std::string rtp_port, rtp_ip, addr_type;
    733   GetDefaultDestination(candidates, ICE_CANDIDATE_COMPONENT_RTP,
    734                         &rtp_port, &rtp_ip, &addr_type);
    735   // Found default RTP candidate.
    736   // RFC 5245
    737   // The default candidates are added to the SDP as the default
    738   // destination for media.  For streams based on RTP, this is done by
    739   // placing the IP address and port of the RTP candidate into the c and m
    740   // lines, respectively.
    741   // Update the port in the m line.
    742   // If this is a m-line with port equal to 0, we don't change it.
    743   if (fields[1] != kMediaPortRejected) {
    744     new_lines.replace(fields[0].size() + 1,
    745                       fields[1].size(),
    746                       rtp_port);
    747   }
    748   // Add the c line.
    749   // RFC 4566
    750   // c=<nettype> <addrtype> <connection-address>
    751   InitLine(kLineTypeConnection, kConnectionNettype, &os);
    752   os << " " << addr_type << " " << rtp_ip;
    753   AddLine(os.str(), &new_lines);
    754   message->append(new_lines);
    755 }
    756 
    757 // Gets "a=rtcp" line if found default RTCP candidate from |candidates|.
    758 static std::string GetRtcpLine(const std::vector<Candidate>& candidates) {
    759   std::string rtcp_line, rtcp_port, rtcp_ip, addr_type;
    760   GetDefaultDestination(candidates, ICE_CANDIDATE_COMPONENT_RTCP,
    761                         &rtcp_port, &rtcp_ip, &addr_type);
    762   // Found default RTCP candidate.
    763   // RFC 5245
    764   // If the agent is utilizing RTCP, it MUST encode the RTCP candidate
    765   // using the a=rtcp attribute as defined in RFC 3605.
    766 
    767   // RFC 3605
    768   // rtcp-attribute =  "a=rtcp:" port  [nettype space addrtype space
    769   // connection-address] CRLF
    770   std::ostringstream os;
    771   InitAttrLine(kAttributeRtcp, &os);
    772   os << kSdpDelimiterColon
    773      << rtcp_port << " "
    774      << kConnectionNettype << " "
    775      << addr_type << " "
    776      << rtcp_ip;
    777   rtcp_line = os.str();
    778   return rtcp_line;
    779 }
    780 
    781 // Get candidates according to the mline index from SessionDescriptionInterface.
    782 static void GetCandidatesByMindex(const SessionDescriptionInterface& desci,
    783                                   int mline_index,
    784                                   std::vector<Candidate>* candidates) {
    785   if (!candidates) {
    786     return;
    787   }
    788   const IceCandidateCollection* cc = desci.candidates(mline_index);
    789   for (size_t i = 0; i < cc->count(); ++i) {
    790     const IceCandidateInterface* candidate = cc->at(i);
    791     candidates->push_back(candidate->candidate());
    792   }
    793 }
    794 
    795 std::string SdpSerialize(const JsepSessionDescription& jdesc) {
    796   const cricket::SessionDescription* desc = jdesc.description();
    797   if (!desc) {
    798     return "";
    799   }
    800 
    801   std::string message;
    802 
    803   // Session Description.
    804   AddLine(kSessionVersion, &message);
    805   // Session Origin
    806   // RFC 4566
    807   // o=<username> <sess-id> <sess-version> <nettype> <addrtype>
    808   // <unicast-address>
    809   std::ostringstream os;
    810   InitLine(kLineTypeOrigin, kSessionOriginUsername, &os);
    811   const std::string& session_id = jdesc.session_id().empty() ?
    812       kSessionOriginSessionId : jdesc.session_id();
    813   const std::string& session_version = jdesc.session_version().empty() ?
    814       kSessionOriginSessionVersion : jdesc.session_version();
    815   os << " " << session_id << " " << session_version << " "
    816      << kSessionOriginNettype << " " << kSessionOriginAddrtype << " "
    817      << kSessionOriginAddress;
    818   AddLine(os.str(), &message);
    819   AddLine(kSessionName, &message);
    820 
    821   // Time Description.
    822   AddLine(kTimeDescription, &message);
    823 
    824   // Group
    825   if (desc->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
    826     std::string group_line = kAttrGroup;
    827     const cricket::ContentGroup* group =
    828         desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
    829     ASSERT(group != NULL);
    830     const cricket::ContentNames& content_names = group->content_names();
    831     for (cricket::ContentNames::const_iterator it = content_names.begin();
    832          it != content_names.end(); ++it) {
    833       group_line.append(" ");
    834       group_line.append(*it);
    835     }
    836     AddLine(group_line, &message);
    837   }
    838 
    839   // MediaStream semantics
    840   InitAttrLine(kAttributeMsidSemantics, &os);
    841   os << kSdpDelimiterColon << " " << kMediaStreamSemantic;
    842 
    843   std::set<std::string> media_stream_labels;
    844   const ContentInfo* audio_content = GetFirstAudioContent(desc);
    845   if (audio_content)
    846     GetMediaStreamLabels(audio_content, &media_stream_labels);
    847 
    848   const ContentInfo* video_content = GetFirstVideoContent(desc);
    849   if (video_content)
    850     GetMediaStreamLabels(video_content, &media_stream_labels);
    851 
    852   for (std::set<std::string>::const_iterator it =
    853       media_stream_labels.begin(); it != media_stream_labels.end(); ++it) {
    854     os << " " << *it;
    855   }
    856   AddLine(os.str(), &message);
    857 
    858   // Preserve the order of the media contents.
    859   int mline_index = -1;
    860   for (cricket::ContentInfos::const_iterator it = desc->contents().begin();
    861        it != desc->contents().end(); ++it) {
    862     const MediaContentDescription* mdesc =
    863       static_cast<const MediaContentDescription*>(it->description);
    864     std::vector<Candidate> candidates;
    865     GetCandidatesByMindex(jdesc, ++mline_index, &candidates);
    866     BuildMediaDescription(&*it,
    867                           desc->GetTransportInfoByName(it->name),
    868                           mdesc->type(),
    869                           candidates,
    870                           &message);
    871   }
    872   return message;
    873 }
    874 
    875 // Serializes the passed in IceCandidateInterface to a SDP string.
    876 // candidate - The candidate to be serialized.
    877 std::string SdpSerializeCandidate(
    878     const IceCandidateInterface& candidate) {
    879   std::string message;
    880   std::vector<cricket::Candidate> candidates;
    881   candidates.push_back(candidate.candidate());
    882   BuildCandidate(candidates, true, &message);
    883   // From WebRTC draft section 4.8.1.1 candidate-attribute will be
    884   // just candidate:<candidate> not a=candidate:<blah>CRLF
    885   ASSERT(message.find("a=") == 0);
    886   message.erase(0, 2);
    887   ASSERT(message.find(kLineBreak) == message.size() - 2);
    888   message.resize(message.size() - 2);
    889   return message;
    890 }
    891 
    892 bool SdpDeserialize(const std::string& message,
    893                     JsepSessionDescription* jdesc,
    894                     SdpParseError* error) {
    895   std::string session_id;
    896   std::string session_version;
    897   TransportDescription session_td("", "");
    898   RtpHeaderExtensions session_extmaps;
    899   cricket::SessionDescription* desc = new cricket::SessionDescription();
    900   std::vector<JsepIceCandidate*> candidates;
    901   size_t current_pos = 0;
    902 
    903   // Session Description
    904   if (!ParseSessionDescription(message, &current_pos, &session_id,
    905                                &session_version, &session_td, &session_extmaps,
    906                                desc, error)) {
    907     delete desc;
    908     return false;
    909   }
    910 
    911   // Media Description
    912   if (!ParseMediaDescription(message, session_td, session_extmaps, &current_pos,
    913                              desc, &candidates, error)) {
    914     delete desc;
    915     for (std::vector<JsepIceCandidate*>::const_iterator
    916          it = candidates.begin(); it != candidates.end(); ++it) {
    917       delete *it;
    918     }
    919     return false;
    920   }
    921 
    922   jdesc->Initialize(desc, session_id, session_version);
    923 
    924   for (std::vector<JsepIceCandidate*>::const_iterator
    925        it = candidates.begin(); it != candidates.end(); ++it) {
    926     jdesc->AddCandidate(*it);
    927     delete *it;
    928   }
    929   return true;
    930 }
    931 
    932 bool SdpDeserializeCandidate(const std::string& message,
    933                              JsepIceCandidate* jcandidate,
    934                              SdpParseError* error) {
    935   ASSERT(jcandidate != NULL);
    936   Candidate candidate;
    937   if (!ParseCandidate(message, &candidate, error, true)) {
    938     return false;
    939   }
    940   jcandidate->SetCandidate(candidate);
    941   return true;
    942 }
    943 
    944 bool ParseCandidate(const std::string& message, Candidate* candidate,
    945                     SdpParseError* error, bool is_raw) {
    946   ASSERT(candidate != NULL);
    947 
    948   // Get the first line from |message|.
    949   std::string first_line = message;
    950   size_t pos = 0;
    951   GetLine(message, &pos, &first_line);
    952 
    953   // Makes sure |message| contains only one line.
    954   if (message.size() > first_line.size()) {
    955     std::string left, right;
    956     if (rtc::tokenize_first(message, kNewLine, &left, &right) &&
    957         !right.empty()) {
    958       return ParseFailed(message, 0, "Expect one line only", error);
    959     }
    960   }
    961 
    962   // From WebRTC draft section 4.8.1.1 candidate-attribute should be
    963   // candidate:<candidate> when trickled, but we still support
    964   // a=candidate:<blah>CRLF for backward compatibility and for parsing a line
    965   // from the SDP.
    966   if (IsLineType(first_line, kLineTypeAttributes)) {
    967     first_line = first_line.substr(kLinePrefixLength);
    968   }
    969 
    970   std::string attribute_candidate;
    971   std::string candidate_value;
    972 
    973   // |first_line| must be in the form of "candidate:<value>".
    974   if (!rtc::tokenize_first(first_line, kSdpDelimiterColon, &attribute_candidate,
    975                            &candidate_value) ||
    976       attribute_candidate != kAttributeCandidate) {
    977     if (is_raw) {
    978       std::ostringstream description;
    979       description << "Expect line: " << kAttributeCandidate
    980                   << ":" << "<candidate-str>";
    981       return ParseFailed(first_line, 0, description.str(), error);
    982     } else {
    983       return ParseFailedExpectLine(first_line, 0, kLineTypeAttributes,
    984                                    kAttributeCandidate, error);
    985     }
    986   }
    987 
    988   std::vector<std::string> fields;
    989   rtc::split(candidate_value, kSdpDelimiterSpace, &fields);
    990 
    991   // RFC 5245
    992   // a=candidate:<foundation> <component-id> <transport> <priority>
    993   // <connection-address> <port> typ <candidate-types>
    994   // [raddr <connection-address>] [rport <port>]
    995   // *(SP extension-att-name SP extension-att-value)
    996   const size_t expected_min_fields = 8;
    997   if (fields.size() < expected_min_fields ||
    998       (fields[6] != kAttributeCandidateTyp)) {
    999     return ParseFailedExpectMinFieldNum(first_line, expected_min_fields, error);
   1000   }
   1001   const std::string& foundation = fields[0];
   1002 
   1003   int component_id = 0;
   1004   if (!GetValueFromString(first_line, fields[1], &component_id, error)) {
   1005     return false;
   1006   }
   1007   const std::string& transport = fields[2];
   1008   uint32_t priority = 0;
   1009   if (!GetValueFromString(first_line, fields[3], &priority, error)) {
   1010     return false;
   1011   }
   1012   const std::string& connection_address = fields[4];
   1013   int port = 0;
   1014   if (!GetValueFromString(first_line, fields[5], &port, error)) {
   1015     return false;
   1016   }
   1017   SocketAddress address(connection_address, port);
   1018 
   1019   cricket::ProtocolType protocol;
   1020   if (!StringToProto(transport.c_str(), &protocol)) {
   1021     return ParseFailed(first_line, "Unsupported transport type.", error);
   1022   }
   1023 
   1024   std::string candidate_type;
   1025   const std::string& type = fields[7];
   1026   if (type == kCandidateHost) {
   1027     candidate_type = cricket::LOCAL_PORT_TYPE;
   1028   } else if (type == kCandidateSrflx) {
   1029     candidate_type = cricket::STUN_PORT_TYPE;
   1030   } else if (type == kCandidateRelay) {
   1031     candidate_type = cricket::RELAY_PORT_TYPE;
   1032   } else {
   1033     return ParseFailed(first_line, "Unsupported candidate type.", error);
   1034   }
   1035 
   1036   size_t current_position = expected_min_fields;
   1037   SocketAddress related_address;
   1038   // The 2 optional fields for related address
   1039   // [raddr <connection-address>] [rport <port>]
   1040   if (fields.size() >= (current_position + 2) &&
   1041       fields[current_position] == kAttributeCandidateRaddr) {
   1042     related_address.SetIP(fields[++current_position]);
   1043     ++current_position;
   1044   }
   1045   if (fields.size() >= (current_position + 2) &&
   1046       fields[current_position] == kAttributeCandidateRport) {
   1047     int port = 0;
   1048     if (!GetValueFromString(
   1049         first_line, fields[++current_position], &port, error)) {
   1050       return false;
   1051     }
   1052     related_address.SetPort(port);
   1053     ++current_position;
   1054   }
   1055 
   1056   // If this is a TCP candidate, it has additional extension as defined in
   1057   // RFC 6544.
   1058   std::string tcptype;
   1059   if (fields.size() >= (current_position + 2) &&
   1060       fields[current_position] == kTcpCandidateType) {
   1061     tcptype = fields[++current_position];
   1062     ++current_position;
   1063 
   1064     if (tcptype != cricket::TCPTYPE_ACTIVE_STR &&
   1065         tcptype != cricket::TCPTYPE_PASSIVE_STR &&
   1066         tcptype != cricket::TCPTYPE_SIMOPEN_STR) {
   1067       return ParseFailed(first_line, "Invalid TCP candidate type.", error);
   1068     }
   1069 
   1070     if (protocol != cricket::PROTO_TCP) {
   1071       return ParseFailed(first_line, "Invalid non-TCP candidate", error);
   1072     }
   1073   }
   1074 
   1075   // Extension
   1076   // Though non-standard, we support the ICE ufrag and pwd being signaled on
   1077   // the candidate to avoid issues with confusing which generation a candidate
   1078   // belongs to when trickling multiple generations at the same time.
   1079   std::string username;
   1080   std::string password;
   1081   uint32_t generation = 0;
   1082   for (size_t i = current_position; i + 1 < fields.size(); ++i) {
   1083     // RFC 5245
   1084     // *(SP extension-att-name SP extension-att-value)
   1085     if (fields[i] == kAttributeCandidateGeneration) {
   1086       if (!GetValueFromString(first_line, fields[++i], &generation, error)) {
   1087         return false;
   1088       }
   1089     } else if (fields[i] == kAttributeCandidateUfrag) {
   1090       username = fields[++i];
   1091     } else if (fields[i] == kAttributeCandidatePwd) {
   1092       password = fields[++i];
   1093     } else {
   1094       // Skip the unknown extension.
   1095       ++i;
   1096     }
   1097   }
   1098 
   1099   *candidate = Candidate(component_id, cricket::ProtoToString(protocol),
   1100                          address, priority, username, password, candidate_type,
   1101                          generation, foundation);
   1102   candidate->set_related_address(related_address);
   1103   candidate->set_tcptype(tcptype);
   1104   return true;
   1105 }
   1106 
   1107 bool ParseIceOptions(const std::string& line,
   1108                      std::vector<std::string>* transport_options,
   1109                      SdpParseError* error) {
   1110   std::string ice_options;
   1111   if (!GetValue(line, kAttributeIceOption, &ice_options, error)) {
   1112     return false;
   1113   }
   1114   std::vector<std::string> fields;
   1115   rtc::split(ice_options, kSdpDelimiterSpace, &fields);
   1116   for (size_t i = 0; i < fields.size(); ++i) {
   1117     transport_options->push_back(fields[i]);
   1118   }
   1119   return true;
   1120 }
   1121 
   1122 bool ParseSctpPort(const std::string& line,
   1123                    int* sctp_port,
   1124                    SdpParseError* error) {
   1125   // draft-ietf-mmusic-sctp-sdp-07
   1126   // a=sctp-port
   1127   std::vector<std::string> fields;
   1128   const size_t expected_min_fields = 2;
   1129   rtc::split(line.substr(kLinePrefixLength), kSdpDelimiterColon, &fields);
   1130   if (fields.size() < expected_min_fields) {
   1131     fields.resize(0);
   1132     rtc::split(line.substr(kLinePrefixLength), kSdpDelimiterSpace, &fields);
   1133   }
   1134   if (fields.size() < expected_min_fields) {
   1135     return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   1136   }
   1137   if (!rtc::FromString(fields[1], sctp_port)) {
   1138     return ParseFailed(line, "Invalid sctp port value.", error);
   1139   }
   1140   return true;
   1141 }
   1142 
   1143 bool ParseExtmap(const std::string& line, RtpHeaderExtension* extmap,
   1144                  SdpParseError* error) {
   1145   // RFC 5285
   1146   // a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
   1147   std::vector<std::string> fields;
   1148   rtc::split(line.substr(kLinePrefixLength),
   1149                    kSdpDelimiterSpace, &fields);
   1150   const size_t expected_min_fields = 2;
   1151   if (fields.size() < expected_min_fields) {
   1152     return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   1153   }
   1154   std::string uri = fields[1];
   1155 
   1156   std::string value_direction;
   1157   if (!GetValue(fields[0], kAttributeExtmap, &value_direction, error)) {
   1158     return false;
   1159   }
   1160   std::vector<std::string> sub_fields;
   1161   rtc::split(value_direction, kSdpDelimiterSlash, &sub_fields);
   1162   int value = 0;
   1163   if (!GetValueFromString(line, sub_fields[0], &value, error)) {
   1164     return false;
   1165   }
   1166 
   1167   *extmap = RtpHeaderExtension(uri, value);
   1168   return true;
   1169 }
   1170 
   1171 void BuildMediaDescription(const ContentInfo* content_info,
   1172                            const TransportInfo* transport_info,
   1173                            const MediaType media_type,
   1174                            const std::vector<Candidate>& candidates,
   1175                            std::string* message) {
   1176   ASSERT(message != NULL);
   1177   if (content_info == NULL || message == NULL) {
   1178     return;
   1179   }
   1180   // TODO: Rethink if we should use sprintfn instead of stringstream.
   1181   // According to the style guide, streams should only be used for logging.
   1182   // http://google-styleguide.googlecode.com/svn/
   1183   // trunk/cppguide.xml?showone=Streams#Streams
   1184   std::ostringstream os;
   1185   const MediaContentDescription* media_desc =
   1186       static_cast<const MediaContentDescription*>(
   1187           content_info->description);
   1188   ASSERT(media_desc != NULL);
   1189 
   1190   int sctp_port = cricket::kSctpDefaultPort;
   1191 
   1192   // RFC 4566
   1193   // m=<media> <port> <proto> <fmt>
   1194   // fmt is a list of payload type numbers that MAY be used in the session.
   1195   const char* type = NULL;
   1196   if (media_type == cricket::MEDIA_TYPE_AUDIO)
   1197     type = kMediaTypeAudio;
   1198   else if (media_type == cricket::MEDIA_TYPE_VIDEO)
   1199     type = kMediaTypeVideo;
   1200   else if (media_type == cricket::MEDIA_TYPE_DATA)
   1201     type = kMediaTypeData;
   1202   else
   1203     ASSERT(false);
   1204 
   1205   std::string fmt;
   1206   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   1207     const VideoContentDescription* video_desc =
   1208         static_cast<const VideoContentDescription*>(media_desc);
   1209     for (std::vector<cricket::VideoCodec>::const_iterator it =
   1210              video_desc->codecs().begin();
   1211          it != video_desc->codecs().end(); ++it) {
   1212       fmt.append(" ");
   1213       fmt.append(rtc::ToString<int>(it->id));
   1214     }
   1215   } else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   1216     const AudioContentDescription* audio_desc =
   1217         static_cast<const AudioContentDescription*>(media_desc);
   1218     for (std::vector<cricket::AudioCodec>::const_iterator it =
   1219              audio_desc->codecs().begin();
   1220          it != audio_desc->codecs().end(); ++it) {
   1221       fmt.append(" ");
   1222       fmt.append(rtc::ToString<int>(it->id));
   1223     }
   1224   } else if (media_type == cricket::MEDIA_TYPE_DATA) {
   1225     const DataContentDescription* data_desc =
   1226           static_cast<const DataContentDescription*>(media_desc);
   1227     if (IsDtlsSctp(media_desc->protocol())) {
   1228       fmt.append(" ");
   1229 
   1230       for (std::vector<cricket::DataCodec>::const_iterator it =
   1231            data_desc->codecs().begin();
   1232            it != data_desc->codecs().end(); ++it) {
   1233         if (it->id == cricket::kGoogleSctpDataCodecId &&
   1234             it->GetParam(cricket::kCodecParamPort, &sctp_port)) {
   1235           break;
   1236         }
   1237       }
   1238 
   1239       fmt.append(rtc::ToString<int>(sctp_port));
   1240     } else {
   1241       for (std::vector<cricket::DataCodec>::const_iterator it =
   1242            data_desc->codecs().begin();
   1243            it != data_desc->codecs().end(); ++it) {
   1244         fmt.append(" ");
   1245         fmt.append(rtc::ToString<int>(it->id));
   1246       }
   1247     }
   1248   }
   1249   // The fmt must never be empty. If no codecs are found, set the fmt attribute
   1250   // to 0.
   1251   if (fmt.empty()) {
   1252     fmt = " 0";
   1253   }
   1254 
   1255   // The port number in the m line will be updated later when associate with
   1256   // the candidates.
   1257   // RFC 3264
   1258   // To reject an offered stream, the port number in the corresponding stream in
   1259   // the answer MUST be set to zero.
   1260   const std::string& port = content_info->rejected ?
   1261       kMediaPortRejected : kDummyPort;
   1262 
   1263   rtc::SSLFingerprint* fp = (transport_info) ?
   1264       transport_info->description.identity_fingerprint.get() : NULL;
   1265 
   1266   // Add the m and c lines.
   1267   InitLine(kLineTypeMedia, type, &os);
   1268   os << " " << port << " " << media_desc->protocol() << fmt;
   1269   std::string mline = os.str();
   1270   UpdateMediaDefaultDestination(candidates, mline, message);
   1271 
   1272   // RFC 4566
   1273   // b=AS:<bandwidth>
   1274   if (media_desc->bandwidth() >= 1000) {
   1275     InitLine(kLineTypeSessionBandwidth, kApplicationSpecificMaximum, &os);
   1276     os << kSdpDelimiterColon << (media_desc->bandwidth() / 1000);
   1277     AddLine(os.str(), message);
   1278   }
   1279 
   1280   // Add the a=rtcp line.
   1281   if (IsRtp(media_desc->protocol())) {
   1282     std::string rtcp_line = GetRtcpLine(candidates);
   1283     if (!rtcp_line.empty()) {
   1284       AddLine(rtcp_line, message);
   1285     }
   1286   }
   1287 
   1288   // Build the a=candidate lines. We don't include ufrag and pwd in the
   1289   // candidates in the SDP to avoid redundancy.
   1290   BuildCandidate(candidates, false, message);
   1291 
   1292   // Use the transport_info to build the media level ice-ufrag and ice-pwd.
   1293   if (transport_info) {
   1294     // RFC 5245
   1295     // ice-pwd-att           = "ice-pwd" ":" password
   1296     // ice-ufrag-att         = "ice-ufrag" ":" ufrag
   1297     // ice-ufrag
   1298     if (!transport_info->description.ice_ufrag.empty()) {
   1299       InitAttrLine(kAttributeIceUfrag, &os);
   1300       os << kSdpDelimiterColon << transport_info->description.ice_ufrag;
   1301       AddLine(os.str(), message);
   1302     }
   1303     // ice-pwd
   1304     if (!transport_info->description.ice_pwd.empty()) {
   1305       InitAttrLine(kAttributeIcePwd, &os);
   1306       os << kSdpDelimiterColon << transport_info->description.ice_pwd;
   1307       AddLine(os.str(), message);
   1308     }
   1309 
   1310     // draft-petithuguenin-mmusic-ice-attributes-level-03
   1311     BuildIceOptions(transport_info->description.transport_options, message);
   1312 
   1313     // RFC 4572
   1314     // fingerprint-attribute  =
   1315     //   "fingerprint" ":" hash-func SP fingerprint
   1316     if (fp) {
   1317       // Insert the fingerprint attribute.
   1318       InitAttrLine(kAttributeFingerprint, &os);
   1319       os << kSdpDelimiterColon
   1320          << fp->algorithm << kSdpDelimiterSpace
   1321          << fp->GetRfc4572Fingerprint();
   1322       AddLine(os.str(), message);
   1323 
   1324       // Inserting setup attribute.
   1325       if (transport_info->description.connection_role !=
   1326               cricket::CONNECTIONROLE_NONE) {
   1327         // Making sure we are not using "passive" mode.
   1328         cricket::ConnectionRole role =
   1329             transport_info->description.connection_role;
   1330         std::string dtls_role_str;
   1331         VERIFY(cricket::ConnectionRoleToString(role, &dtls_role_str));
   1332         InitAttrLine(kAttributeSetup, &os);
   1333         os << kSdpDelimiterColon << dtls_role_str;
   1334         AddLine(os.str(), message);
   1335       }
   1336     }
   1337   }
   1338 
   1339   // RFC 3388
   1340   // mid-attribute      = "a=mid:" identification-tag
   1341   // identification-tag = token
   1342   // Use the content name as the mid identification-tag.
   1343   InitAttrLine(kAttributeMid, &os);
   1344   os << kSdpDelimiterColon << content_info->name;
   1345   AddLine(os.str(), message);
   1346 
   1347   if (IsDtlsSctp(media_desc->protocol())) {
   1348     BuildSctpContentAttributes(message, sctp_port);
   1349   } else if (IsRtp(media_desc->protocol())) {
   1350     BuildRtpContentAttributes(media_desc, media_type, message);
   1351   }
   1352 }
   1353 
   1354 void BuildSctpContentAttributes(std::string* message, int sctp_port) {
   1355   // draft-ietf-mmusic-sctp-sdp-04
   1356   // a=sctpmap:sctpmap-number  protocol  [streams]
   1357   // TODO(lally): switch this over to mmusic-sctp-sdp-12 (or later), with
   1358   // 'a=sctp-port:'
   1359   std::ostringstream os;
   1360   InitAttrLine(kAttributeSctpmap, &os);
   1361   os << kSdpDelimiterColon << sctp_port << kSdpDelimiterSpace
   1362      << kDefaultSctpmapProtocol << kSdpDelimiterSpace
   1363      << (cricket::kMaxSctpSid + 1);
   1364   AddLine(os.str(), message);
   1365 }
   1366 
   1367 void BuildRtpContentAttributes(
   1368     const MediaContentDescription* media_desc,
   1369     const MediaType media_type,
   1370     std::string* message) {
   1371   std::ostringstream os;
   1372   // RFC 5285
   1373   // a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
   1374   // The definitions MUST be either all session level or all media level. This
   1375   // implementation uses all media level.
   1376   for (size_t i = 0; i < media_desc->rtp_header_extensions().size(); ++i) {
   1377     InitAttrLine(kAttributeExtmap, &os);
   1378     os << kSdpDelimiterColon << media_desc->rtp_header_extensions()[i].id
   1379        << kSdpDelimiterSpace << media_desc->rtp_header_extensions()[i].uri;
   1380     AddLine(os.str(), message);
   1381   }
   1382 
   1383   // RFC 3264
   1384   // a=sendrecv || a=sendonly || a=sendrecv || a=inactive
   1385   switch (media_desc->direction()) {
   1386     case cricket::MD_INACTIVE:
   1387       InitAttrLine(kAttributeInactive, &os);
   1388       break;
   1389     case cricket::MD_SENDONLY:
   1390       InitAttrLine(kAttributeSendOnly, &os);
   1391       break;
   1392     case cricket::MD_RECVONLY:
   1393       InitAttrLine(kAttributeRecvOnly, &os);
   1394       break;
   1395     case cricket::MD_SENDRECV:
   1396     default:
   1397       InitAttrLine(kAttributeSendRecv, &os);
   1398       break;
   1399   }
   1400   AddLine(os.str(), message);
   1401 
   1402   // RFC 5761
   1403   // a=rtcp-mux
   1404   if (media_desc->rtcp_mux()) {
   1405     InitAttrLine(kAttributeRtcpMux, &os);
   1406     AddLine(os.str(), message);
   1407   }
   1408 
   1409   // RFC 5506
   1410   // a=rtcp-rsize
   1411   if (media_desc->rtcp_reduced_size()) {
   1412     InitAttrLine(kAttributeRtcpReducedSize, &os);
   1413     AddLine(os.str(), message);
   1414   }
   1415 
   1416   // RFC 4568
   1417   // a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
   1418   for (std::vector<CryptoParams>::const_iterator it =
   1419            media_desc->cryptos().begin();
   1420        it != media_desc->cryptos().end(); ++it) {
   1421     InitAttrLine(kAttributeCrypto, &os);
   1422     os << kSdpDelimiterColon << it->tag << " " << it->cipher_suite << " "
   1423        << it->key_params;
   1424     if (!it->session_params.empty()) {
   1425       os << " " << it->session_params;
   1426     }
   1427     AddLine(os.str(), message);
   1428   }
   1429 
   1430   // RFC 4566
   1431   // a=rtpmap:<payload type> <encoding name>/<clock rate>
   1432   // [/<encodingparameters>]
   1433   BuildRtpMap(media_desc, media_type, message);
   1434 
   1435   for (StreamParamsVec::const_iterator track = media_desc->streams().begin();
   1436        track != media_desc->streams().end(); ++track) {
   1437     // Require that the track belongs to a media stream,
   1438     // ie the sync_label is set. This extra check is necessary since the
   1439     // MediaContentDescription always contains a streamparam with an ssrc even
   1440     // if no track or media stream have been created.
   1441     if (track->sync_label.empty()) continue;
   1442 
   1443     // Build the ssrc-group lines.
   1444     for (size_t i = 0; i < track->ssrc_groups.size(); ++i) {
   1445       // RFC 5576
   1446       // a=ssrc-group:<semantics> <ssrc-id> ...
   1447       if (track->ssrc_groups[i].ssrcs.empty()) {
   1448         continue;
   1449       }
   1450       std::ostringstream os;
   1451       InitAttrLine(kAttributeSsrcGroup, &os);
   1452       os << kSdpDelimiterColon << track->ssrc_groups[i].semantics;
   1453       std::vector<uint32_t>::const_iterator ssrc =
   1454           track->ssrc_groups[i].ssrcs.begin();
   1455       for (; ssrc != track->ssrc_groups[i].ssrcs.end(); ++ssrc) {
   1456         os << kSdpDelimiterSpace << rtc::ToString<uint32_t>(*ssrc);
   1457       }
   1458       AddLine(os.str(), message);
   1459     }
   1460     // Build the ssrc lines for each ssrc.
   1461     for (size_t i = 0; i < track->ssrcs.size(); ++i) {
   1462       uint32_t ssrc = track->ssrcs[i];
   1463       // RFC 5576
   1464       // a=ssrc:<ssrc-id> cname:<value>
   1465       AddSsrcLine(ssrc, kSsrcAttributeCname,
   1466                   track->cname, message);
   1467 
   1468       // draft-alvestrand-mmusic-msid-00
   1469       // a=ssrc:<ssrc-id> msid:identifier [appdata]
   1470       // The appdata consists of the "id" attribute of a MediaStreamTrack, which
   1471       // is corresponding to the "name" attribute of StreamParams.
   1472       std::string appdata = track->id;
   1473       std::ostringstream os;
   1474       InitAttrLine(kAttributeSsrc, &os);
   1475       os << kSdpDelimiterColon << ssrc << kSdpDelimiterSpace
   1476          << kSsrcAttributeMsid << kSdpDelimiterColon << track->sync_label
   1477          << kSdpDelimiterSpace << appdata;
   1478       AddLine(os.str(), message);
   1479 
   1480       // TODO(ronghuawu): Remove below code which is for backward compatibility.
   1481       // draft-alvestrand-rtcweb-mid-01
   1482       // a=ssrc:<ssrc-id> mslabel:<value>
   1483       // The label isn't yet defined.
   1484       // a=ssrc:<ssrc-id> label:<value>
   1485       AddSsrcLine(ssrc, kSsrcAttributeMslabel, track->sync_label, message);
   1486       AddSsrcLine(ssrc, kSSrcAttributeLabel, track->id, message);
   1487     }
   1488   }
   1489 }
   1490 
   1491 void WriteFmtpHeader(int payload_type, std::ostringstream* os) {
   1492   // fmtp header: a=fmtp:|payload_type| <parameters>
   1493   // Add a=fmtp
   1494   InitAttrLine(kAttributeFmtp, os);
   1495   // Add :|payload_type|
   1496   *os << kSdpDelimiterColon << payload_type;
   1497 }
   1498 
   1499 void WriteRtcpFbHeader(int payload_type, std::ostringstream* os) {
   1500   // rtcp-fb header: a=rtcp-fb:|payload_type|
   1501   // <parameters>/<ccm <ccm_parameters>>
   1502   // Add a=rtcp-fb
   1503   InitAttrLine(kAttributeRtcpFb, os);
   1504   // Add :
   1505   *os << kSdpDelimiterColon;
   1506   if (payload_type == kWildcardPayloadType) {
   1507     *os << "*";
   1508   } else {
   1509     *os << payload_type;
   1510   }
   1511 }
   1512 
   1513 void WriteFmtpParameter(const std::string& parameter_name,
   1514                         const std::string& parameter_value,
   1515                         std::ostringstream* os) {
   1516   // fmtp parameters: |parameter_name|=|parameter_value|
   1517   *os << parameter_name << kSdpDelimiterEqual << parameter_value;
   1518 }
   1519 
   1520 void WriteFmtpParameters(const cricket::CodecParameterMap& parameters,
   1521                          std::ostringstream* os) {
   1522   for (cricket::CodecParameterMap::const_iterator fmtp = parameters.begin();
   1523        fmtp != parameters.end(); ++fmtp) {
   1524     // Each new parameter, except the first one starts with ";" and " ".
   1525     if (fmtp != parameters.begin()) {
   1526       *os << kSdpDelimiterSemicolon;
   1527     }
   1528     *os << kSdpDelimiterSpace;
   1529     WriteFmtpParameter(fmtp->first, fmtp->second, os);
   1530   }
   1531 }
   1532 
   1533 bool IsFmtpParam(const std::string& name) {
   1534   const char* kFmtpParams[] = {
   1535     kCodecParamMinPTime, kCodecParamSPropStereo,
   1536     kCodecParamStereo, kCodecParamUseInbandFec, kCodecParamUseDtx,
   1537     kCodecParamStartBitrate, kCodecParamMaxBitrate, kCodecParamMinBitrate,
   1538     kCodecParamMaxQuantization, kCodecParamSctpProtocol, kCodecParamSctpStreams,
   1539     kCodecParamMaxAverageBitrate, kCodecParamMaxPlaybackRate,
   1540     kCodecParamAssociatedPayloadType
   1541   };
   1542   for (size_t i = 0; i < arraysize(kFmtpParams); ++i) {
   1543     if (_stricmp(name.c_str(), kFmtpParams[i]) == 0) {
   1544       return true;
   1545     }
   1546   }
   1547   return false;
   1548 }
   1549 
   1550 // Retreives fmtp parameters from |params|, which may contain other parameters
   1551 // as well, and puts them in |fmtp_parameters|.
   1552 void GetFmtpParams(const cricket::CodecParameterMap& params,
   1553                    cricket::CodecParameterMap* fmtp_parameters) {
   1554   for (cricket::CodecParameterMap::const_iterator iter = params.begin();
   1555        iter != params.end(); ++iter) {
   1556     if (IsFmtpParam(iter->first)) {
   1557       (*fmtp_parameters)[iter->first] = iter->second;
   1558     }
   1559   }
   1560 }
   1561 
   1562 template <class T>
   1563 void AddFmtpLine(const T& codec, std::string* message) {
   1564   cricket::CodecParameterMap fmtp_parameters;
   1565   GetFmtpParams(codec.params, &fmtp_parameters);
   1566   if (fmtp_parameters.empty()) {
   1567     // No need to add an fmtp if it will have no (optional) parameters.
   1568     return;
   1569   }
   1570   std::ostringstream os;
   1571   WriteFmtpHeader(codec.id, &os);
   1572   WriteFmtpParameters(fmtp_parameters, &os);
   1573   AddLine(os.str(), message);
   1574   return;
   1575 }
   1576 
   1577 template <class T>
   1578 void AddRtcpFbLines(const T& codec, std::string* message) {
   1579   for (std::vector<cricket::FeedbackParam>::const_iterator iter =
   1580            codec.feedback_params.params().begin();
   1581        iter != codec.feedback_params.params().end(); ++iter) {
   1582     std::ostringstream os;
   1583     WriteRtcpFbHeader(codec.id, &os);
   1584     os << " " << iter->id();
   1585     if (!iter->param().empty()) {
   1586       os << " " << iter->param();
   1587     }
   1588     AddLine(os.str(), message);
   1589   }
   1590 }
   1591 
   1592 bool AddSctpDataCodec(DataContentDescription* media_desc,
   1593                       int sctp_port) {
   1594   if (media_desc->HasCodec(cricket::kGoogleSctpDataCodecId)) {
   1595     return ParseFailed("",
   1596                        "Can't have multiple sctp port attributes.",
   1597                        NULL);
   1598   }
   1599   // Add the SCTP Port number as a pseudo-codec "port" parameter
   1600   cricket::DataCodec codec_port(
   1601       cricket::kGoogleSctpDataCodecId, cricket::kGoogleSctpDataCodecName,
   1602       0);
   1603   codec_port.SetParam(cricket::kCodecParamPort, sctp_port);
   1604   LOG(INFO) << "AddSctpDataCodec: Got SCTP Port Number "
   1605             << sctp_port;
   1606   media_desc->AddCodec(codec_port);
   1607   return true;
   1608 }
   1609 
   1610 bool GetMinValue(const std::vector<int>& values, int* value) {
   1611   if (values.empty()) {
   1612     return false;
   1613   }
   1614   std::vector<int>::const_iterator found =
   1615       std::min_element(values.begin(), values.end());
   1616   *value = *found;
   1617   return true;
   1618 }
   1619 
   1620 bool GetParameter(const std::string& name,
   1621                   const cricket::CodecParameterMap& params, int* value) {
   1622   std::map<std::string, std::string>::const_iterator found =
   1623       params.find(name);
   1624   if (found == params.end()) {
   1625     return false;
   1626   }
   1627   if (!rtc::FromString(found->second, value)) {
   1628     return false;
   1629   }
   1630   return true;
   1631 }
   1632 
   1633 void BuildRtpMap(const MediaContentDescription* media_desc,
   1634                  const MediaType media_type,
   1635                  std::string* message) {
   1636   ASSERT(message != NULL);
   1637   ASSERT(media_desc != NULL);
   1638   std::ostringstream os;
   1639   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   1640     const VideoContentDescription* video_desc =
   1641         static_cast<const VideoContentDescription*>(media_desc);
   1642     for (std::vector<cricket::VideoCodec>::const_iterator it =
   1643              video_desc->codecs().begin();
   1644          it != video_desc->codecs().end(); ++it) {
   1645       // RFC 4566
   1646       // a=rtpmap:<payload type> <encoding name>/<clock rate>
   1647       // [/<encodingparameters>]
   1648       if (it->id != kWildcardPayloadType) {
   1649         InitAttrLine(kAttributeRtpmap, &os);
   1650         os << kSdpDelimiterColon << it->id << " " << it->name
   1651          << "/" << kDefaultVideoClockrate;
   1652         AddLine(os.str(), message);
   1653       }
   1654       AddRtcpFbLines(*it, message);
   1655       AddFmtpLine(*it, message);
   1656     }
   1657   } else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   1658     const AudioContentDescription* audio_desc =
   1659         static_cast<const AudioContentDescription*>(media_desc);
   1660     std::vector<int> ptimes;
   1661     std::vector<int> maxptimes;
   1662     int max_minptime = 0;
   1663     for (std::vector<cricket::AudioCodec>::const_iterator it =
   1664              audio_desc->codecs().begin();
   1665          it != audio_desc->codecs().end(); ++it) {
   1666       ASSERT(!it->name.empty());
   1667       // RFC 4566
   1668       // a=rtpmap:<payload type> <encoding name>/<clock rate>
   1669       // [/<encodingparameters>]
   1670       InitAttrLine(kAttributeRtpmap, &os);
   1671       os << kSdpDelimiterColon << it->id << " ";
   1672       os << it->name << "/" << it->clockrate;
   1673       if (it->channels != 1) {
   1674         os << "/" << it->channels;
   1675       }
   1676       AddLine(os.str(), message);
   1677       AddRtcpFbLines(*it, message);
   1678       AddFmtpLine(*it, message);
   1679       int minptime = 0;
   1680       if (GetParameter(kCodecParamMinPTime, it->params, &minptime)) {
   1681         max_minptime = std::max(minptime, max_minptime);
   1682       }
   1683       int ptime;
   1684       if (GetParameter(kCodecParamPTime, it->params, &ptime)) {
   1685         ptimes.push_back(ptime);
   1686       }
   1687       int maxptime;
   1688       if (GetParameter(kCodecParamMaxPTime, it->params, &maxptime)) {
   1689         maxptimes.push_back(maxptime);
   1690       }
   1691     }
   1692     // Populate the maxptime attribute with the smallest maxptime of all codecs
   1693     // under the same m-line.
   1694     int min_maxptime = INT_MAX;
   1695     if (GetMinValue(maxptimes, &min_maxptime)) {
   1696       AddAttributeLine(kCodecParamMaxPTime, min_maxptime, message);
   1697     }
   1698     ASSERT(min_maxptime > max_minptime);
   1699     // Populate the ptime attribute with the smallest ptime or the largest
   1700     // minptime, whichever is the largest, for all codecs under the same m-line.
   1701     int ptime = INT_MAX;
   1702     if (GetMinValue(ptimes, &ptime)) {
   1703       ptime = std::min(ptime, min_maxptime);
   1704       ptime = std::max(ptime, max_minptime);
   1705       AddAttributeLine(kCodecParamPTime, ptime, message);
   1706     }
   1707   } else if (media_type == cricket::MEDIA_TYPE_DATA) {
   1708     const DataContentDescription* data_desc =
   1709         static_cast<const DataContentDescription*>(media_desc);
   1710     for (std::vector<cricket::DataCodec>::const_iterator it =
   1711          data_desc->codecs().begin();
   1712          it != data_desc->codecs().end(); ++it) {
   1713       // RFC 4566
   1714       // a=rtpmap:<payload type> <encoding name>/<clock rate>
   1715       // [/<encodingparameters>]
   1716       InitAttrLine(kAttributeRtpmap, &os);
   1717       os << kSdpDelimiterColon << it->id << " "
   1718          << it->name << "/" << it->clockrate;
   1719       AddLine(os.str(), message);
   1720     }
   1721   }
   1722 }
   1723 
   1724 void BuildCandidate(const std::vector<Candidate>& candidates,
   1725                     bool include_ufrag,
   1726                     std::string* message) {
   1727   std::ostringstream os;
   1728 
   1729   for (std::vector<Candidate>::const_iterator it = candidates.begin();
   1730        it != candidates.end(); ++it) {
   1731     // RFC 5245
   1732     // a=candidate:<foundation> <component-id> <transport> <priority>
   1733     // <connection-address> <port> typ <candidate-types>
   1734     // [raddr <connection-address>] [rport <port>]
   1735     // *(SP extension-att-name SP extension-att-value)
   1736     std::string type;
   1737     // Map the cricket candidate type to "host" / "srflx" / "prflx" / "relay"
   1738     if (it->type() == cricket::LOCAL_PORT_TYPE) {
   1739       type = kCandidateHost;
   1740     } else if (it->type() == cricket::STUN_PORT_TYPE) {
   1741       type = kCandidateSrflx;
   1742     } else if (it->type() == cricket::RELAY_PORT_TYPE) {
   1743       type = kCandidateRelay;
   1744     } else {
   1745       ASSERT(false);
   1746       // Never write out candidates if we don't know the type.
   1747       continue;
   1748     }
   1749 
   1750     InitAttrLine(kAttributeCandidate, &os);
   1751     os << kSdpDelimiterColon
   1752        << it->foundation() << " "
   1753        << it->component() << " "
   1754        << it->protocol() << " "
   1755        << it->priority() << " "
   1756        << it->address().ipaddr().ToString() << " "
   1757        << it->address().PortAsString() << " "
   1758        << kAttributeCandidateTyp << " "
   1759        << type << " ";
   1760 
   1761     // Related address
   1762     if (!it->related_address().IsNil()) {
   1763       os << kAttributeCandidateRaddr << " "
   1764          << it->related_address().ipaddr().ToString() << " "
   1765          << kAttributeCandidateRport << " "
   1766          << it->related_address().PortAsString() << " ";
   1767     }
   1768 
   1769     if (it->protocol() == cricket::TCP_PROTOCOL_NAME) {
   1770       os << kTcpCandidateType << " " << it->tcptype() << " ";
   1771     }
   1772 
   1773     // Extensions
   1774     os << kAttributeCandidateGeneration << " " << it->generation();
   1775     if (include_ufrag && !it->username().empty()) {
   1776       os << " " << kAttributeCandidateUfrag << " " << it->username();
   1777     }
   1778 
   1779     AddLine(os.str(), message);
   1780   }
   1781 }
   1782 
   1783 void BuildIceOptions(const std::vector<std::string>& transport_options,
   1784                      std::string* message) {
   1785   if (!transport_options.empty()) {
   1786     std::ostringstream os;
   1787     InitAttrLine(kAttributeIceOption, &os);
   1788     os << kSdpDelimiterColon << transport_options[0];
   1789     for (size_t i = 1; i < transport_options.size(); ++i) {
   1790       os << kSdpDelimiterSpace << transport_options[i];
   1791     }
   1792     AddLine(os.str(), message);
   1793   }
   1794 }
   1795 
   1796 bool IsRtp(const std::string& protocol) {
   1797   return protocol.empty() ||
   1798       (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
   1799 }
   1800 
   1801 bool IsDtlsSctp(const std::string& protocol) {
   1802   // This intentionally excludes "SCTP" and "SCTP/DTLS".
   1803   return protocol.find(cricket::kMediaProtocolDtlsSctp) != std::string::npos;
   1804 }
   1805 
   1806 bool ParseSessionDescription(const std::string& message, size_t* pos,
   1807                              std::string* session_id,
   1808                              std::string* session_version,
   1809                              TransportDescription* session_td,
   1810                              RtpHeaderExtensions* session_extmaps,
   1811                              cricket::SessionDescription* desc,
   1812                              SdpParseError* error) {
   1813   std::string line;
   1814 
   1815   desc->set_msid_supported(false);
   1816 
   1817   // RFC 4566
   1818   // v=  (protocol version)
   1819   if (!GetLineWithType(message, pos, &line, kLineTypeVersion)) {
   1820     return ParseFailedExpectLine(message, *pos, kLineTypeVersion,
   1821                                  std::string(), error);
   1822   }
   1823   // RFC 4566
   1824   // o=<username> <sess-id> <sess-version> <nettype> <addrtype>
   1825   // <unicast-address>
   1826   if (!GetLineWithType(message, pos, &line, kLineTypeOrigin)) {
   1827     return ParseFailedExpectLine(message, *pos, kLineTypeOrigin,
   1828                                  std::string(), error);
   1829   }
   1830   std::vector<std::string> fields;
   1831   rtc::split(line.substr(kLinePrefixLength),
   1832                    kSdpDelimiterSpace, &fields);
   1833   const size_t expected_fields = 6;
   1834   if (fields.size() != expected_fields) {
   1835     return ParseFailedExpectFieldNum(line, expected_fields, error);
   1836   }
   1837   *session_id = fields[1];
   1838   *session_version = fields[2];
   1839 
   1840   // RFC 4566
   1841   // s=  (session name)
   1842   if (!GetLineWithType(message, pos, &line, kLineTypeSessionName)) {
   1843     return ParseFailedExpectLine(message, *pos, kLineTypeSessionName,
   1844                                  std::string(), error);
   1845   }
   1846 
   1847   // Optional lines
   1848   // Those are the optional lines, so shouldn't return false if not present.
   1849   // RFC 4566
   1850   // i=* (session information)
   1851   GetLineWithType(message, pos, &line, kLineTypeSessionInfo);
   1852 
   1853   // RFC 4566
   1854   // u=* (URI of description)
   1855   GetLineWithType(message, pos, &line, kLineTypeSessionUri);
   1856 
   1857   // RFC 4566
   1858   // e=* (email address)
   1859   GetLineWithType(message, pos, &line, kLineTypeSessionEmail);
   1860 
   1861   // RFC 4566
   1862   // p=* (phone number)
   1863   GetLineWithType(message, pos, &line, kLineTypeSessionPhone);
   1864 
   1865   // RFC 4566
   1866   // c=* (connection information -- not required if included in
   1867   //      all media)
   1868   GetLineWithType(message, pos, &line, kLineTypeConnection);
   1869 
   1870   // RFC 4566
   1871   // b=* (zero or more bandwidth information lines)
   1872   while (GetLineWithType(message, pos, &line, kLineTypeSessionBandwidth)) {
   1873     // By pass zero or more b lines.
   1874   }
   1875 
   1876   // RFC 4566
   1877   // One or more time descriptions ("t=" and "r=" lines; see below)
   1878   // t=  (time the session is active)
   1879   // r=* (zero or more repeat times)
   1880   // Ensure there's at least one time description
   1881   if (!GetLineWithType(message, pos, &line, kLineTypeTiming)) {
   1882     return ParseFailedExpectLine(message, *pos, kLineTypeTiming, std::string(),
   1883                                  error);
   1884   }
   1885 
   1886   while (GetLineWithType(message, pos, &line, kLineTypeRepeatTimes)) {
   1887     // By pass zero or more r lines.
   1888   }
   1889 
   1890   // Go through the rest of the time descriptions
   1891   while (GetLineWithType(message, pos, &line, kLineTypeTiming)) {
   1892     while (GetLineWithType(message, pos, &line, kLineTypeRepeatTimes)) {
   1893       // By pass zero or more r lines.
   1894     }
   1895   }
   1896 
   1897   // RFC 4566
   1898   // z=* (time zone adjustments)
   1899   GetLineWithType(message, pos, &line, kLineTypeTimeZone);
   1900 
   1901   // RFC 4566
   1902   // k=* (encryption key)
   1903   GetLineWithType(message, pos, &line, kLineTypeEncryptionKey);
   1904 
   1905   // RFC 4566
   1906   // a=* (zero or more session attribute lines)
   1907   while (GetLineWithType(message, pos, &line, kLineTypeAttributes)) {
   1908     if (HasAttribute(line, kAttributeGroup)) {
   1909       if (!ParseGroupAttribute(line, desc, error)) {
   1910         return false;
   1911       }
   1912     } else if (HasAttribute(line, kAttributeIceUfrag)) {
   1913       if (!GetValue(line, kAttributeIceUfrag,
   1914                     &(session_td->ice_ufrag), error)) {
   1915         return false;
   1916       }
   1917     } else if (HasAttribute(line, kAttributeIcePwd)) {
   1918       if (!GetValue(line, kAttributeIcePwd, &(session_td->ice_pwd), error)) {
   1919         return false;
   1920       }
   1921     } else if (HasAttribute(line, kAttributeIceLite)) {
   1922       session_td->ice_mode = cricket::ICEMODE_LITE;
   1923     } else if (HasAttribute(line, kAttributeIceOption)) {
   1924       if (!ParseIceOptions(line, &(session_td->transport_options), error)) {
   1925         return false;
   1926       }
   1927     } else if (HasAttribute(line, kAttributeFingerprint)) {
   1928       if (session_td->identity_fingerprint.get()) {
   1929         return ParseFailed(
   1930             line,
   1931             "Can't have multiple fingerprint attributes at the same level.",
   1932             error);
   1933       }
   1934       rtc::SSLFingerprint* fingerprint = NULL;
   1935       if (!ParseFingerprintAttribute(line, &fingerprint, error)) {
   1936         return false;
   1937       }
   1938       session_td->identity_fingerprint.reset(fingerprint);
   1939     } else if (HasAttribute(line, kAttributeSetup)) {
   1940       if (!ParseDtlsSetup(line, &(session_td->connection_role), error)) {
   1941         return false;
   1942       }
   1943     } else if (HasAttribute(line, kAttributeMsidSemantics)) {
   1944       std::string semantics;
   1945       if (!GetValue(line, kAttributeMsidSemantics, &semantics, error)) {
   1946         return false;
   1947       }
   1948       desc->set_msid_supported(
   1949           CaseInsensitiveFind(semantics, kMediaStreamSemantic));
   1950     } else if (HasAttribute(line, kAttributeExtmap)) {
   1951       RtpHeaderExtension extmap;
   1952       if (!ParseExtmap(line, &extmap, error)) {
   1953         return false;
   1954       }
   1955       session_extmaps->push_back(extmap);
   1956     }
   1957   }
   1958 
   1959   return true;
   1960 }
   1961 
   1962 bool ParseGroupAttribute(const std::string& line,
   1963                          cricket::SessionDescription* desc,
   1964                          SdpParseError* error) {
   1965   ASSERT(desc != NULL);
   1966 
   1967   // RFC 5888 and draft-holmberg-mmusic-sdp-bundle-negotiation-00
   1968   // a=group:BUNDLE video voice
   1969   std::vector<std::string> fields;
   1970   rtc::split(line.substr(kLinePrefixLength),
   1971                    kSdpDelimiterSpace, &fields);
   1972   std::string semantics;
   1973   if (!GetValue(fields[0], kAttributeGroup, &semantics, error)) {
   1974     return false;
   1975   }
   1976   cricket::ContentGroup group(semantics);
   1977   for (size_t i = 1; i < fields.size(); ++i) {
   1978     group.AddContentName(fields[i]);
   1979   }
   1980   desc->AddGroup(group);
   1981   return true;
   1982 }
   1983 
   1984 static bool ParseFingerprintAttribute(const std::string& line,
   1985                                       rtc::SSLFingerprint** fingerprint,
   1986                                       SdpParseError* error) {
   1987   if (!IsLineType(line, kLineTypeAttributes) ||
   1988       !HasAttribute(line, kAttributeFingerprint)) {
   1989     return ParseFailedExpectLine(line, 0, kLineTypeAttributes,
   1990                                  kAttributeFingerprint, error);
   1991   }
   1992 
   1993   std::vector<std::string> fields;
   1994   rtc::split(line.substr(kLinePrefixLength),
   1995                    kSdpDelimiterSpace, &fields);
   1996   const size_t expected_fields = 2;
   1997   if (fields.size() != expected_fields) {
   1998     return ParseFailedExpectFieldNum(line, expected_fields, error);
   1999   }
   2000 
   2001   // The first field here is "fingerprint:<hash>.
   2002   std::string algorithm;
   2003   if (!GetValue(fields[0], kAttributeFingerprint, &algorithm, error)) {
   2004     return false;
   2005   }
   2006 
   2007   // Downcase the algorithm. Note that we don't need to downcase the
   2008   // fingerprint because hex_decode can handle upper-case.
   2009   std::transform(algorithm.begin(), algorithm.end(), algorithm.begin(),
   2010                  ::tolower);
   2011 
   2012   // The second field is the digest value. De-hexify it.
   2013   *fingerprint = rtc::SSLFingerprint::CreateFromRfc4572(
   2014       algorithm, fields[1]);
   2015   if (!*fingerprint) {
   2016     return ParseFailed(line,
   2017                        "Failed to create fingerprint from the digest.",
   2018                        error);
   2019   }
   2020 
   2021   return true;
   2022 }
   2023 
   2024 static bool ParseDtlsSetup(const std::string& line,
   2025                            cricket::ConnectionRole* role,
   2026                            SdpParseError* error) {
   2027   // setup-attr           =  "a=setup:" role
   2028   // role                 =  "active" / "passive" / "actpass" / "holdconn"
   2029   std::vector<std::string> fields;
   2030   rtc::split(line.substr(kLinePrefixLength), kSdpDelimiterColon, &fields);
   2031   const size_t expected_fields = 2;
   2032   if (fields.size() != expected_fields) {
   2033     return ParseFailedExpectFieldNum(line, expected_fields, error);
   2034   }
   2035   std::string role_str = fields[1];
   2036   if (!cricket::StringToConnectionRole(role_str, role)) {
   2037     return ParseFailed(line, "Invalid attribute value.", error);
   2038   }
   2039   return true;
   2040 }
   2041 
   2042 // RFC 3551
   2043 //  PT   encoding    media type  clock rate   channels
   2044 //                      name                    (Hz)
   2045 //  0    PCMU        A            8,000       1
   2046 //  1    reserved    A
   2047 //  2    reserved    A
   2048 //  3    GSM         A            8,000       1
   2049 //  4    G723        A            8,000       1
   2050 //  5    DVI4        A            8,000       1
   2051 //  6    DVI4        A           16,000       1
   2052 //  7    LPC         A            8,000       1
   2053 //  8    PCMA        A            8,000       1
   2054 //  9    G722        A            8,000       1
   2055 //  10   L16         A           44,100       2
   2056 //  11   L16         A           44,100       1
   2057 //  12   QCELP       A            8,000       1
   2058 //  13   CN          A            8,000       1
   2059 //  14   MPA         A           90,000       (see text)
   2060 //  15   G728        A            8,000       1
   2061 //  16   DVI4        A           11,025       1
   2062 //  17   DVI4        A           22,050       1
   2063 //  18   G729        A            8,000       1
   2064 struct StaticPayloadAudioCodec {
   2065   const char* name;
   2066   int clockrate;
   2067   size_t channels;
   2068 };
   2069 static const StaticPayloadAudioCodec kStaticPayloadAudioCodecs[] = {
   2070   { "PCMU", 8000, 1 },
   2071   { "reserved", 0, 0 },
   2072   { "reserved", 0, 0 },
   2073   { "GSM", 8000, 1 },
   2074   { "G723", 8000, 1 },
   2075   { "DVI4", 8000, 1 },
   2076   { "DVI4", 16000, 1 },
   2077   { "LPC", 8000, 1 },
   2078   { "PCMA", 8000, 1 },
   2079   { "G722", 8000, 1 },
   2080   { "L16", 44100, 2 },
   2081   { "L16", 44100, 1 },
   2082   { "QCELP", 8000, 1 },
   2083   { "CN", 8000, 1 },
   2084   { "MPA", 90000, 1 },
   2085   { "G728", 8000, 1 },
   2086   { "DVI4", 11025, 1 },
   2087   { "DVI4", 22050, 1 },
   2088   { "G729", 8000, 1 },
   2089 };
   2090 
   2091 void MaybeCreateStaticPayloadAudioCodecs(
   2092     const std::vector<int>& fmts, AudioContentDescription* media_desc) {
   2093   if (!media_desc) {
   2094     return;
   2095   }
   2096   int preference = static_cast<int>(fmts.size());
   2097   std::vector<int>::const_iterator it = fmts.begin();
   2098   bool add_new_codec = false;
   2099   for (; it != fmts.end(); ++it) {
   2100     int payload_type = *it;
   2101     if (!media_desc->HasCodec(payload_type) &&
   2102         payload_type >= 0 &&
   2103         payload_type < arraysize(kStaticPayloadAudioCodecs)) {
   2104       std::string encoding_name = kStaticPayloadAudioCodecs[payload_type].name;
   2105       int clock_rate = kStaticPayloadAudioCodecs[payload_type].clockrate;
   2106       size_t channels = kStaticPayloadAudioCodecs[payload_type].channels;
   2107       media_desc->AddCodec(cricket::AudioCodec(payload_type, encoding_name,
   2108                                                clock_rate, 0, channels,
   2109                                                preference));
   2110       add_new_codec = true;
   2111     }
   2112     --preference;
   2113   }
   2114   if (add_new_codec) {
   2115     media_desc->SortCodecs();
   2116   }
   2117 }
   2118 
   2119 template <class C>
   2120 static C* ParseContentDescription(const std::string& message,
   2121                                   const MediaType media_type,
   2122                                   int mline_index,
   2123                                   const std::string& protocol,
   2124                                   const std::vector<int>& codec_preference,
   2125                                   size_t* pos,
   2126                                   std::string* content_name,
   2127                                   TransportDescription* transport,
   2128                                   std::vector<JsepIceCandidate*>* candidates,
   2129                                   webrtc::SdpParseError* error) {
   2130   C* media_desc = new C();
   2131   switch (media_type) {
   2132     case cricket::MEDIA_TYPE_AUDIO:
   2133       *content_name = cricket::CN_AUDIO;
   2134       break;
   2135     case cricket::MEDIA_TYPE_VIDEO:
   2136       *content_name = cricket::CN_VIDEO;
   2137       break;
   2138     case cricket::MEDIA_TYPE_DATA:
   2139       *content_name = cricket::CN_DATA;
   2140       break;
   2141     default:
   2142       ASSERT(false);
   2143       break;
   2144   }
   2145   if (!ParseContent(message, media_type, mline_index, protocol,
   2146                     codec_preference, pos, content_name,
   2147                     media_desc, transport, candidates, error)) {
   2148     delete media_desc;
   2149     return NULL;
   2150   }
   2151   // Sort the codecs according to the m-line fmt list.
   2152   media_desc->SortCodecs();
   2153   return media_desc;
   2154 }
   2155 
   2156 bool ParseMediaDescription(const std::string& message,
   2157                            const TransportDescription& session_td,
   2158                            const RtpHeaderExtensions& session_extmaps,
   2159                            size_t* pos,
   2160                            cricket::SessionDescription* desc,
   2161                            std::vector<JsepIceCandidate*>* candidates,
   2162                            SdpParseError* error) {
   2163   ASSERT(desc != NULL);
   2164   std::string line;
   2165   int mline_index = -1;
   2166 
   2167   // Zero or more media descriptions
   2168   // RFC 4566
   2169   // m=<media> <port> <proto> <fmt>
   2170   while (GetLineWithType(message, pos, &line, kLineTypeMedia)) {
   2171     ++mline_index;
   2172 
   2173     std::vector<std::string> fields;
   2174     rtc::split(line.substr(kLinePrefixLength),
   2175                      kSdpDelimiterSpace, &fields);
   2176     const size_t expected_min_fields = 4;
   2177     if (fields.size() < expected_min_fields) {
   2178       return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   2179     }
   2180     bool rejected = false;
   2181     // RFC 3264
   2182     // To reject an offered stream, the port number in the corresponding stream
   2183     // in the answer MUST be set to zero.
   2184     if (fields[1] == kMediaPortRejected) {
   2185       rejected = true;
   2186     }
   2187 
   2188     std::string protocol = fields[2];
   2189 
   2190     // <fmt>
   2191     std::vector<int> codec_preference;
   2192     if (IsRtp(protocol)) {
   2193       for (size_t j = 3 ; j < fields.size(); ++j) {
   2194         // TODO(wu): Remove when below bug is fixed.
   2195         // https://bugzilla.mozilla.org/show_bug.cgi?id=996329
   2196         if (fields[j].empty() && j == fields.size() - 1) {
   2197           continue;
   2198         }
   2199 
   2200         int pl = 0;
   2201         if (!GetPayloadTypeFromString(line, fields[j], &pl, error)) {
   2202           return false;
   2203         }
   2204         codec_preference.push_back(pl);
   2205       }
   2206     }
   2207 
   2208     // Make a temporary TransportDescription based on |session_td|.
   2209     // Some of this gets overwritten by ParseContent.
   2210     TransportDescription transport(session_td.transport_options,
   2211                                    session_td.ice_ufrag,
   2212                                    session_td.ice_pwd,
   2213                                    session_td.ice_mode,
   2214                                    session_td.connection_role,
   2215                                    session_td.identity_fingerprint.get(),
   2216                                    Candidates());
   2217 
   2218     rtc::scoped_ptr<MediaContentDescription> content;
   2219     std::string content_name;
   2220     if (HasAttribute(line, kMediaTypeVideo)) {
   2221       content.reset(ParseContentDescription<VideoContentDescription>(
   2222                     message, cricket::MEDIA_TYPE_VIDEO, mline_index, protocol,
   2223                     codec_preference, pos, &content_name,
   2224                     &transport, candidates, error));
   2225     } else if (HasAttribute(line, kMediaTypeAudio)) {
   2226       content.reset(ParseContentDescription<AudioContentDescription>(
   2227                     message, cricket::MEDIA_TYPE_AUDIO, mline_index, protocol,
   2228                     codec_preference, pos, &content_name,
   2229                     &transport, candidates, error));
   2230     } else if (HasAttribute(line, kMediaTypeData)) {
   2231       DataContentDescription* data_desc =
   2232           ParseContentDescription<DataContentDescription>(
   2233                     message, cricket::MEDIA_TYPE_DATA, mline_index, protocol,
   2234                     codec_preference, pos, &content_name,
   2235                     &transport, candidates, error);
   2236       content.reset(data_desc);
   2237 
   2238       int p;
   2239       if (data_desc && IsDtlsSctp(protocol) && rtc::FromString(fields[3], &p)) {
   2240         if (!AddSctpDataCodec(data_desc, p))
   2241           return false;
   2242       }
   2243     } else {
   2244       LOG(LS_WARNING) << "Unsupported media type: " << line;
   2245       continue;
   2246     }
   2247     if (!content.get()) {
   2248       // ParseContentDescription returns NULL if failed.
   2249       return false;
   2250     }
   2251 
   2252     if (IsRtp(protocol)) {
   2253       // Set the extmap.
   2254       if (!session_extmaps.empty() &&
   2255           !content->rtp_header_extensions().empty()) {
   2256         return ParseFailed("",
   2257                            "The a=extmap MUST be either all session level or "
   2258                            "all media level.",
   2259                            error);
   2260       }
   2261       for (size_t i = 0; i < session_extmaps.size(); ++i) {
   2262         content->AddRtpHeaderExtension(session_extmaps[i]);
   2263       }
   2264     }
   2265     content->set_protocol(protocol);
   2266     desc->AddContent(content_name,
   2267                      IsDtlsSctp(protocol) ? cricket::NS_JINGLE_DRAFT_SCTP :
   2268                                             cricket::NS_JINGLE_RTP,
   2269                      rejected,
   2270                      content.release());
   2271     // Create TransportInfo with the media level "ice-pwd" and "ice-ufrag".
   2272     TransportInfo transport_info(content_name, transport);
   2273 
   2274     if (!desc->AddTransportInfo(transport_info)) {
   2275       std::ostringstream description;
   2276       description << "Failed to AddTransportInfo with content name: "
   2277                   << content_name;
   2278       return ParseFailed("", description.str(), error);
   2279     }
   2280   }
   2281 
   2282   size_t end_of_message = message.size();
   2283   if (mline_index == -1 && *pos != end_of_message) {
   2284     ParseFailed(message, *pos, "Expects m line.", error);
   2285     return false;
   2286   }
   2287   return true;
   2288 }
   2289 
   2290 bool VerifyCodec(const cricket::Codec& codec) {
   2291   // Codec has not been populated correctly unless the name has been set. This
   2292   // can happen if an SDP has an fmtp or rtcp-fb with a payload type but doesn't
   2293   // have a corresponding "rtpmap" line.
   2294   cricket::Codec default_codec;
   2295   return default_codec.name != codec.name;
   2296 }
   2297 
   2298 bool VerifyAudioCodecs(const AudioContentDescription* audio_desc) {
   2299   const std::vector<cricket::AudioCodec>& codecs = audio_desc->codecs();
   2300   for (std::vector<cricket::AudioCodec>::const_iterator iter = codecs.begin();
   2301        iter != codecs.end(); ++iter) {
   2302     if (!VerifyCodec(*iter)) {
   2303       return false;
   2304     }
   2305   }
   2306   return true;
   2307 }
   2308 
   2309 bool VerifyVideoCodecs(const VideoContentDescription* video_desc) {
   2310   const std::vector<cricket::VideoCodec>& codecs = video_desc->codecs();
   2311   for (std::vector<cricket::VideoCodec>::const_iterator iter = codecs.begin();
   2312        iter != codecs.end(); ++iter) {
   2313     if (!VerifyCodec(*iter)) {
   2314       return false;
   2315     }
   2316   }
   2317   return true;
   2318 }
   2319 
   2320 void AddParameters(const cricket::CodecParameterMap& parameters,
   2321                    cricket::Codec* codec) {
   2322   for (cricket::CodecParameterMap::const_iterator iter =
   2323            parameters.begin(); iter != parameters.end(); ++iter) {
   2324     codec->SetParam(iter->first, iter->second);
   2325   }
   2326 }
   2327 
   2328 void AddFeedbackParameter(const cricket::FeedbackParam& feedback_param,
   2329                           cricket::Codec* codec) {
   2330   codec->AddFeedbackParam(feedback_param);
   2331 }
   2332 
   2333 void AddFeedbackParameters(const cricket::FeedbackParams& feedback_params,
   2334                            cricket::Codec* codec) {
   2335   for (std::vector<cricket::FeedbackParam>::const_iterator iter =
   2336            feedback_params.params().begin();
   2337        iter != feedback_params.params().end(); ++iter) {
   2338     codec->AddFeedbackParam(*iter);
   2339   }
   2340 }
   2341 
   2342 // Gets the current codec setting associated with |payload_type|. If there
   2343 // is no Codec associated with that payload type it returns an empty codec
   2344 // with that payload type.
   2345 template <class T>
   2346 T GetCodecWithPayloadType(const std::vector<T>& codecs, int payload_type) {
   2347   T ret_val;
   2348   if (!FindCodecById(codecs, payload_type, &ret_val)) {
   2349     ret_val.id = payload_type;
   2350   }
   2351   return ret_val;
   2352 }
   2353 
   2354 // Updates or creates a new codec entry in the audio description.
   2355 template <class T, class U>
   2356 void AddOrReplaceCodec(MediaContentDescription* content_desc, const U& codec) {
   2357   T* desc = static_cast<T*>(content_desc);
   2358   std::vector<U> codecs = desc->codecs();
   2359   bool found = false;
   2360 
   2361   typename std::vector<U>::iterator iter;
   2362   for (iter = codecs.begin(); iter != codecs.end(); ++iter) {
   2363     if (iter->id == codec.id) {
   2364       *iter = codec;
   2365       found = true;
   2366       break;
   2367     }
   2368   }
   2369   if (!found) {
   2370     desc->AddCodec(codec);
   2371     return;
   2372   }
   2373   desc->set_codecs(codecs);
   2374 }
   2375 
   2376 // Adds or updates existing codec corresponding to |payload_type| according
   2377 // to |parameters|.
   2378 template <class T, class U>
   2379 void UpdateCodec(MediaContentDescription* content_desc, int payload_type,
   2380                  const cricket::CodecParameterMap& parameters) {
   2381   // Codec might already have been populated (from rtpmap).
   2382   U new_codec = GetCodecWithPayloadType(static_cast<T*>(content_desc)->codecs(),
   2383                                         payload_type);
   2384   AddParameters(parameters, &new_codec);
   2385   AddOrReplaceCodec<T, U>(content_desc, new_codec);
   2386 }
   2387 
   2388 // Adds or updates existing codec corresponding to |payload_type| according
   2389 // to |feedback_param|.
   2390 template <class T, class U>
   2391 void UpdateCodec(MediaContentDescription* content_desc, int payload_type,
   2392                  const cricket::FeedbackParam& feedback_param) {
   2393   // Codec might already have been populated (from rtpmap).
   2394   U new_codec = GetCodecWithPayloadType(static_cast<T*>(content_desc)->codecs(),
   2395                                         payload_type);
   2396   AddFeedbackParameter(feedback_param, &new_codec);
   2397   AddOrReplaceCodec<T, U>(content_desc, new_codec);
   2398 }
   2399 
   2400 template <class T>
   2401 bool PopWildcardCodec(std::vector<T>* codecs, T* wildcard_codec) {
   2402   for (auto iter = codecs->begin(); iter != codecs->end(); ++iter) {
   2403     if (iter->id == kWildcardPayloadType) {
   2404       *wildcard_codec = *iter;
   2405       codecs->erase(iter);
   2406       return true;
   2407     }
   2408   }
   2409   return false;
   2410 }
   2411 
   2412 template<class T>
   2413 void UpdateFromWildcardCodecs(cricket::MediaContentDescriptionImpl<T>* desc) {
   2414   auto codecs = desc->codecs();
   2415   T wildcard_codec;
   2416   if (!PopWildcardCodec(&codecs, &wildcard_codec)) {
   2417     return;
   2418   }
   2419   for (auto& codec : codecs) {
   2420     AddFeedbackParameters(wildcard_codec.feedback_params, &codec);
   2421   }
   2422   desc->set_codecs(codecs);
   2423 }
   2424 
   2425 void AddAudioAttribute(const std::string& name, const std::string& value,
   2426                        AudioContentDescription* audio_desc) {
   2427   if (value.empty()) {
   2428     return;
   2429   }
   2430   std::vector<cricket::AudioCodec> codecs = audio_desc->codecs();
   2431   for (std::vector<cricket::AudioCodec>::iterator iter = codecs.begin();
   2432        iter != codecs.end(); ++iter) {
   2433     iter->params[name] = value;
   2434   }
   2435   audio_desc->set_codecs(codecs);
   2436 }
   2437 
   2438 bool ParseContent(const std::string& message,
   2439                   const MediaType media_type,
   2440                   int mline_index,
   2441                   const std::string& protocol,
   2442                   const std::vector<int>& codec_preference,
   2443                   size_t* pos,
   2444                   std::string* content_name,
   2445                   MediaContentDescription* media_desc,
   2446                   TransportDescription* transport,
   2447                   std::vector<JsepIceCandidate*>* candidates,
   2448                   SdpParseError* error) {
   2449   ASSERT(media_desc != NULL);
   2450   ASSERT(content_name != NULL);
   2451   ASSERT(transport != NULL);
   2452 
   2453   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   2454     MaybeCreateStaticPayloadAudioCodecs(
   2455         codec_preference, static_cast<AudioContentDescription*>(media_desc));
   2456   }
   2457 
   2458   // The media level "ice-ufrag" and "ice-pwd".
   2459   // The candidates before update the media level "ice-pwd" and "ice-ufrag".
   2460   Candidates candidates_orig;
   2461   std::string line;
   2462   std::string mline_id;
   2463   // Tracks created out of the ssrc attributes.
   2464   StreamParamsVec tracks;
   2465   SsrcInfoVec ssrc_infos;
   2466   SsrcGroupVec ssrc_groups;
   2467   std::string maxptime_as_string;
   2468   std::string ptime_as_string;
   2469 
   2470   // Loop until the next m line
   2471   while (!IsLineType(message, kLineTypeMedia, *pos)) {
   2472     if (!GetLine(message, pos, &line)) {
   2473       if (*pos >= message.size()) {
   2474         break;  // Done parsing
   2475       } else {
   2476         return ParseFailed(message, *pos, "Invalid SDP line.", error);
   2477       }
   2478     }
   2479 
   2480     // RFC 4566
   2481     // b=* (zero or more bandwidth information lines)
   2482     if (IsLineType(line, kLineTypeSessionBandwidth)) {
   2483       std::string bandwidth;
   2484       if (HasAttribute(line, kApplicationSpecificMaximum)) {
   2485         if (!GetValue(line, kApplicationSpecificMaximum, &bandwidth, error)) {
   2486           return false;
   2487         } else {
   2488           int b = 0;
   2489           if (!GetValueFromString(line, bandwidth, &b, error)) {
   2490             return false;
   2491           }
   2492           // We should never use more than the default bandwidth for RTP-based
   2493           // data channels. Don't allow SDP to set the bandwidth, because
   2494           // that would give JS the opportunity to "break the Internet".
   2495           // See: https://code.google.com/p/chromium/issues/detail?id=280726
   2496           if (media_type == cricket::MEDIA_TYPE_DATA && IsRtp(protocol) &&
   2497               b > cricket::kDataMaxBandwidth / 1000) {
   2498             std::ostringstream description;
   2499             description << "RTP-based data channels may not send more than "
   2500                         << cricket::kDataMaxBandwidth / 1000 << "kbps.";
   2501             return ParseFailed(line, description.str(), error);
   2502           }
   2503           media_desc->set_bandwidth(b * 1000);
   2504         }
   2505       }
   2506       continue;
   2507     }
   2508 
   2509     if (!IsLineType(line, kLineTypeAttributes)) {
   2510       // TODO: Handle other lines if needed.
   2511       LOG(LS_INFO) << "Ignored line: " << line;
   2512       continue;
   2513     }
   2514 
   2515     // Handle attributes common to SCTP and RTP.
   2516     if (HasAttribute(line, kAttributeMid)) {
   2517       // RFC 3388
   2518       // mid-attribute      = "a=mid:" identification-tag
   2519       // identification-tag = token
   2520       // Use the mid identification-tag as the content name.
   2521       if (!GetValue(line, kAttributeMid, &mline_id, error)) {
   2522         return false;
   2523       }
   2524       *content_name = mline_id;
   2525     } else if (HasAttribute(line, kAttributeCandidate)) {
   2526       Candidate candidate;
   2527       if (!ParseCandidate(line, &candidate, error, false)) {
   2528         return false;
   2529       }
   2530       candidates_orig.push_back(candidate);
   2531     } else if (HasAttribute(line, kAttributeIceUfrag)) {
   2532       if (!GetValue(line, kAttributeIceUfrag, &transport->ice_ufrag, error)) {
   2533         return false;
   2534       }
   2535     } else if (HasAttribute(line, kAttributeIcePwd)) {
   2536       if (!GetValue(line, kAttributeIcePwd, &transport->ice_pwd, error)) {
   2537         return false;
   2538       }
   2539     } else if (HasAttribute(line, kAttributeIceOption)) {
   2540       if (!ParseIceOptions(line, &transport->transport_options, error)) {
   2541         return false;
   2542       }
   2543     } else if (HasAttribute(line, kAttributeFmtp)) {
   2544       if (!ParseFmtpAttributes(line, media_type, media_desc, error)) {
   2545         return false;
   2546       }
   2547     } else if (HasAttribute(line, kAttributeFingerprint)) {
   2548       rtc::SSLFingerprint* fingerprint = NULL;
   2549 
   2550       if (!ParseFingerprintAttribute(line, &fingerprint, error)) {
   2551         return false;
   2552       }
   2553       transport->identity_fingerprint.reset(fingerprint);
   2554     } else if (HasAttribute(line, kAttributeSetup)) {
   2555       if (!ParseDtlsSetup(line, &(transport->connection_role), error)) {
   2556         return false;
   2557       }
   2558     } else if (IsDtlsSctp(protocol) && HasAttribute(line, kAttributeSctpPort)) {
   2559       int sctp_port;
   2560       if (!ParseSctpPort(line, &sctp_port, error)) {
   2561         return false;
   2562       }
   2563       if (!AddSctpDataCodec(static_cast<DataContentDescription*>(media_desc),
   2564                             sctp_port)) {
   2565         return false;
   2566       }
   2567     } else if (IsRtp(protocol)) {
   2568       //
   2569       // RTP specific attrubtes
   2570       //
   2571       if (HasAttribute(line, kAttributeRtcpMux)) {
   2572         media_desc->set_rtcp_mux(true);
   2573       } else if (HasAttribute(line, kAttributeRtcpReducedSize)) {
   2574         media_desc->set_rtcp_reduced_size(true);
   2575       } else if (HasAttribute(line, kAttributeSsrcGroup)) {
   2576         if (!ParseSsrcGroupAttribute(line, &ssrc_groups, error)) {
   2577           return false;
   2578         }
   2579       } else if (HasAttribute(line, kAttributeSsrc)) {
   2580         if (!ParseSsrcAttribute(line, &ssrc_infos, error)) {
   2581           return false;
   2582         }
   2583       } else if (HasAttribute(line, kAttributeCrypto)) {
   2584         if (!ParseCryptoAttribute(line, media_desc, error)) {
   2585           return false;
   2586         }
   2587       } else if (HasAttribute(line, kAttributeRtpmap)) {
   2588         if (!ParseRtpmapAttribute(line, media_type, codec_preference,
   2589                                   media_desc, error)) {
   2590           return false;
   2591         }
   2592       } else if (HasAttribute(line, kCodecParamMaxPTime)) {
   2593         if (!GetValue(line, kCodecParamMaxPTime, &maxptime_as_string, error)) {
   2594           return false;
   2595         }
   2596       } else if (HasAttribute(line, kAttributeRtcpFb)) {
   2597         if (!ParseRtcpFbAttribute(line, media_type, media_desc, error)) {
   2598           return false;
   2599         }
   2600       } else if (HasAttribute(line, kCodecParamPTime)) {
   2601         if (!GetValue(line, kCodecParamPTime, &ptime_as_string, error)) {
   2602           return false;
   2603         }
   2604       } else if (HasAttribute(line, kAttributeSendOnly)) {
   2605         media_desc->set_direction(cricket::MD_SENDONLY);
   2606       } else if (HasAttribute(line, kAttributeRecvOnly)) {
   2607         media_desc->set_direction(cricket::MD_RECVONLY);
   2608       } else if (HasAttribute(line, kAttributeInactive)) {
   2609         media_desc->set_direction(cricket::MD_INACTIVE);
   2610       } else if (HasAttribute(line, kAttributeSendRecv)) {
   2611         media_desc->set_direction(cricket::MD_SENDRECV);
   2612       } else if (HasAttribute(line, kAttributeExtmap)) {
   2613         RtpHeaderExtension extmap;
   2614         if (!ParseExtmap(line, &extmap, error)) {
   2615           return false;
   2616         }
   2617         media_desc->AddRtpHeaderExtension(extmap);
   2618       } else if (HasAttribute(line, kAttributeXGoogleFlag)) {
   2619         // Experimental attribute.  Conference mode activates more aggressive
   2620         // AEC and NS settings.
   2621         // TODO: expose API to set these directly.
   2622         std::string flag_value;
   2623         if (!GetValue(line, kAttributeXGoogleFlag, &flag_value, error)) {
   2624           return false;
   2625         }
   2626         if (flag_value.compare(kValueConference) == 0)
   2627           media_desc->set_conference_mode(true);
   2628       }
   2629     } else {
   2630       // Only parse lines that we are interested of.
   2631       LOG(LS_INFO) << "Ignored line: " << line;
   2632       continue;
   2633     }
   2634   }
   2635 
   2636   // Create tracks from the |ssrc_infos|.
   2637   CreateTracksFromSsrcInfos(ssrc_infos, &tracks);
   2638 
   2639   // Add the ssrc group to the track.
   2640   for (SsrcGroupVec::iterator ssrc_group = ssrc_groups.begin();
   2641        ssrc_group != ssrc_groups.end(); ++ssrc_group) {
   2642     if (ssrc_group->ssrcs.empty()) {
   2643       continue;
   2644     }
   2645     uint32_t ssrc = ssrc_group->ssrcs.front();
   2646     for (StreamParamsVec::iterator track = tracks.begin();
   2647          track != tracks.end(); ++track) {
   2648       if (track->has_ssrc(ssrc)) {
   2649         track->ssrc_groups.push_back(*ssrc_group);
   2650       }
   2651     }
   2652   }
   2653 
   2654   // Add the new tracks to the |media_desc|.
   2655   for (StreamParamsVec::iterator track = tracks.begin();
   2656        track != tracks.end(); ++track) {
   2657     media_desc->AddStream(*track);
   2658   }
   2659 
   2660   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   2661     AudioContentDescription* audio_desc =
   2662         static_cast<AudioContentDescription*>(media_desc);
   2663     UpdateFromWildcardCodecs(audio_desc);
   2664 
   2665     // Verify audio codec ensures that no audio codec has been populated with
   2666     // only fmtp.
   2667     if (!VerifyAudioCodecs(audio_desc)) {
   2668       return ParseFailed("Failed to parse audio codecs correctly.", error);
   2669     }
   2670     AddAudioAttribute(kCodecParamMaxPTime, maxptime_as_string, audio_desc);
   2671     AddAudioAttribute(kCodecParamPTime, ptime_as_string, audio_desc);
   2672   }
   2673 
   2674   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   2675     VideoContentDescription* video_desc =
   2676         static_cast<VideoContentDescription*>(media_desc);
   2677     UpdateFromWildcardCodecs(video_desc);
   2678     // Verify video codec ensures that no video codec has been populated with
   2679     // only rtcp-fb.
   2680     if (!VerifyVideoCodecs(video_desc)) {
   2681       return ParseFailed("Failed to parse video codecs correctly.", error);
   2682     }
   2683   }
   2684 
   2685   // RFC 5245
   2686   // Update the candidates with the media level "ice-pwd" and "ice-ufrag".
   2687   for (Candidates::iterator it = candidates_orig.begin();
   2688        it != candidates_orig.end(); ++it) {
   2689     ASSERT((*it).username().empty() ||
   2690            (*it).username() == transport->ice_ufrag);
   2691     (*it).set_username(transport->ice_ufrag);
   2692     ASSERT((*it).password().empty());
   2693     (*it).set_password(transport->ice_pwd);
   2694     candidates->push_back(
   2695         new JsepIceCandidate(mline_id, mline_index, *it));
   2696   }
   2697   return true;
   2698 }
   2699 
   2700 bool ParseSsrcAttribute(const std::string& line, SsrcInfoVec* ssrc_infos,
   2701                         SdpParseError* error) {
   2702   ASSERT(ssrc_infos != NULL);
   2703   // RFC 5576
   2704   // a=ssrc:<ssrc-id> <attribute>
   2705   // a=ssrc:<ssrc-id> <attribute>:<value>
   2706   std::string field1, field2;
   2707   if (!rtc::tokenize_first(line.substr(kLinePrefixLength), kSdpDelimiterSpace,
   2708                            &field1, &field2)) {
   2709     const size_t expected_fields = 2;
   2710     return ParseFailedExpectFieldNum(line, expected_fields, error);
   2711   }
   2712 
   2713   // ssrc:<ssrc-id>
   2714   std::string ssrc_id_s;
   2715   if (!GetValue(field1, kAttributeSsrc, &ssrc_id_s, error)) {
   2716     return false;
   2717   }
   2718   uint32_t ssrc_id = 0;
   2719   if (!GetValueFromString(line, ssrc_id_s, &ssrc_id, error)) {
   2720     return false;
   2721   }
   2722 
   2723   std::string attribute;
   2724   std::string value;
   2725   if (!rtc::tokenize_first(field2, kSdpDelimiterColon, &attribute, &value)) {
   2726     std::ostringstream description;
   2727     description << "Failed to get the ssrc attribute value from " << field2
   2728                 << ". Expected format <attribute>:<value>.";
   2729     return ParseFailed(line, description.str(), error);
   2730   }
   2731 
   2732   // Check if there's already an item for this |ssrc_id|. Create a new one if
   2733   // there isn't.
   2734   SsrcInfoVec::iterator ssrc_info = ssrc_infos->begin();
   2735   for (; ssrc_info != ssrc_infos->end(); ++ssrc_info) {
   2736     if (ssrc_info->ssrc_id == ssrc_id) {
   2737       break;
   2738     }
   2739   }
   2740   if (ssrc_info == ssrc_infos->end()) {
   2741     SsrcInfo info;
   2742     info.ssrc_id = ssrc_id;
   2743     ssrc_infos->push_back(info);
   2744     ssrc_info = ssrc_infos->end() - 1;
   2745   }
   2746 
   2747   // Store the info to the |ssrc_info|.
   2748   if (attribute == kSsrcAttributeCname) {
   2749     // RFC 5576
   2750     // cname:<value>
   2751     ssrc_info->cname = value;
   2752   } else if (attribute == kSsrcAttributeMsid) {
   2753     // draft-alvestrand-mmusic-msid-00
   2754     // "msid:" identifier [ " " appdata ]
   2755     std::vector<std::string> fields;
   2756     rtc::split(value, kSdpDelimiterSpace, &fields);
   2757     if (fields.size() < 1 || fields.size() > 2) {
   2758       return ParseFailed(line,
   2759                          "Expected format \"msid:<identifier>[ <appdata>]\".",
   2760                          error);
   2761     }
   2762     ssrc_info->msid_identifier = fields[0];
   2763     if (fields.size() == 2) {
   2764       ssrc_info->msid_appdata = fields[1];
   2765     }
   2766   } else if (attribute == kSsrcAttributeMslabel) {
   2767     // draft-alvestrand-rtcweb-mid-01
   2768     // mslabel:<value>
   2769     ssrc_info->mslabel = value;
   2770   } else if (attribute == kSSrcAttributeLabel) {
   2771     // The label isn't defined.
   2772     // label:<value>
   2773     ssrc_info->label = value;
   2774   }
   2775   return true;
   2776 }
   2777 
   2778 bool ParseSsrcGroupAttribute(const std::string& line,
   2779                              SsrcGroupVec* ssrc_groups,
   2780                              SdpParseError* error) {
   2781   ASSERT(ssrc_groups != NULL);
   2782   // RFC 5576
   2783   // a=ssrc-group:<semantics> <ssrc-id> ...
   2784   std::vector<std::string> fields;
   2785   rtc::split(line.substr(kLinePrefixLength),
   2786                    kSdpDelimiterSpace, &fields);
   2787   const size_t expected_min_fields = 2;
   2788   if (fields.size() < expected_min_fields) {
   2789     return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   2790   }
   2791   std::string semantics;
   2792   if (!GetValue(fields[0], kAttributeSsrcGroup, &semantics, error)) {
   2793     return false;
   2794   }
   2795   std::vector<uint32_t> ssrcs;
   2796   for (size_t i = 1; i < fields.size(); ++i) {
   2797     uint32_t ssrc = 0;
   2798     if (!GetValueFromString(line, fields[i], &ssrc, error)) {
   2799       return false;
   2800     }
   2801     ssrcs.push_back(ssrc);
   2802   }
   2803   ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
   2804   return true;
   2805 }
   2806 
   2807 bool ParseCryptoAttribute(const std::string& line,
   2808                           MediaContentDescription* media_desc,
   2809                           SdpParseError* error) {
   2810   std::vector<std::string> fields;
   2811   rtc::split(line.substr(kLinePrefixLength),
   2812                    kSdpDelimiterSpace, &fields);
   2813   // RFC 4568
   2814   // a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
   2815   const size_t expected_min_fields = 3;
   2816   if (fields.size() < expected_min_fields) {
   2817     return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   2818   }
   2819   std::string tag_value;
   2820   if (!GetValue(fields[0], kAttributeCrypto, &tag_value, error)) {
   2821     return false;
   2822   }
   2823   int tag = 0;
   2824   if (!GetValueFromString(line, tag_value, &tag, error)) {
   2825     return false;
   2826   }
   2827   const std::string& crypto_suite = fields[1];
   2828   const std::string& key_params = fields[2];
   2829   std::string session_params;
   2830   if (fields.size() > 3) {
   2831     session_params = fields[3];
   2832   }
   2833   media_desc->AddCrypto(CryptoParams(tag, crypto_suite, key_params,
   2834                                      session_params));
   2835   return true;
   2836 }
   2837 
   2838 // Updates or creates a new codec entry in the audio description with according
   2839 // to |name|, |clockrate|, |bitrate|, |channels| and |preference|.
   2840 void UpdateCodec(int payload_type, const std::string& name, int clockrate,
   2841                  int bitrate, size_t channels, int preference,
   2842                  AudioContentDescription* audio_desc) {
   2843   // Codec may already be populated with (only) optional parameters
   2844   // (from an fmtp).
   2845   cricket::AudioCodec codec =
   2846       GetCodecWithPayloadType(audio_desc->codecs(), payload_type);
   2847   codec.name = name;
   2848   codec.clockrate = clockrate;
   2849   codec.bitrate = bitrate;
   2850   codec.channels = channels;
   2851   codec.preference = preference;
   2852   AddOrReplaceCodec<AudioContentDescription, cricket::AudioCodec>(audio_desc,
   2853                                                                   codec);
   2854 }
   2855 
   2856 // Updates or creates a new codec entry in the video description according to
   2857 // |name|, |width|, |height|, |framerate| and |preference|.
   2858 void UpdateCodec(int payload_type, const std::string& name, int width,
   2859                  int height, int framerate, int preference,
   2860                  VideoContentDescription* video_desc) {
   2861   // Codec may already be populated with (only) optional parameters
   2862   // (from an fmtp).
   2863   cricket::VideoCodec codec =
   2864       GetCodecWithPayloadType(video_desc->codecs(), payload_type);
   2865   codec.name = name;
   2866   codec.width = width;
   2867   codec.height = height;
   2868   codec.framerate = framerate;
   2869   codec.preference = preference;
   2870   AddOrReplaceCodec<VideoContentDescription, cricket::VideoCodec>(video_desc,
   2871                                                                   codec);
   2872 }
   2873 
   2874 bool ParseRtpmapAttribute(const std::string& line,
   2875                           const MediaType media_type,
   2876                           const std::vector<int>& codec_preference,
   2877                           MediaContentDescription* media_desc,
   2878                           SdpParseError* error) {
   2879   std::vector<std::string> fields;
   2880   rtc::split(line.substr(kLinePrefixLength),
   2881                    kSdpDelimiterSpace, &fields);
   2882   // RFC 4566
   2883   // a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encodingparameters>]
   2884   const size_t expected_min_fields = 2;
   2885   if (fields.size() < expected_min_fields) {
   2886     return ParseFailedExpectMinFieldNum(line, expected_min_fields, error);
   2887   }
   2888   std::string payload_type_value;
   2889   if (!GetValue(fields[0], kAttributeRtpmap, &payload_type_value, error)) {
   2890     return false;
   2891   }
   2892   int payload_type = 0;
   2893   if (!GetPayloadTypeFromString(line, payload_type_value, &payload_type,
   2894                                 error)) {
   2895     return false;
   2896   }
   2897 
   2898   // Set the preference order depending on the order of the pl type in the
   2899   // <fmt> of the m-line.
   2900   const int preference = codec_preference.end() -
   2901       std::find(codec_preference.begin(), codec_preference.end(),
   2902                 payload_type);
   2903   if (preference == 0) {
   2904     LOG(LS_WARNING) << "Ignore rtpmap line that did not appear in the "
   2905                     << "<fmt> of the m-line: " << line;
   2906     return true;
   2907   }
   2908   const std::string& encoder = fields[1];
   2909   std::vector<std::string> codec_params;
   2910   rtc::split(encoder, '/', &codec_params);
   2911   // <encoding name>/<clock rate>[/<encodingparameters>]
   2912   // 2 mandatory fields
   2913   if (codec_params.size() < 2 || codec_params.size() > 3) {
   2914     return ParseFailed(line,
   2915                        "Expected format \"<encoding name>/<clock rate>"
   2916                        "[/<encodingparameters>]\".",
   2917                        error);
   2918   }
   2919   const std::string& encoding_name = codec_params[0];
   2920   int clock_rate = 0;
   2921   if (!GetValueFromString(line, codec_params[1], &clock_rate, error)) {
   2922     return false;
   2923   }
   2924   if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   2925     VideoContentDescription* video_desc =
   2926         static_cast<VideoContentDescription*>(media_desc);
   2927     // TODO: We will send resolution in SDP. For now use
   2928     // JsepSessionDescription::kMaxVideoCodecWidth and kMaxVideoCodecHeight.
   2929     UpdateCodec(payload_type, encoding_name,
   2930                 JsepSessionDescription::kMaxVideoCodecWidth,
   2931                 JsepSessionDescription::kMaxVideoCodecHeight,
   2932                 JsepSessionDescription::kDefaultVideoCodecFramerate,
   2933                 preference, video_desc);
   2934   } else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   2935     // RFC 4566
   2936     // For audio streams, <encoding parameters> indicates the number
   2937     // of audio channels.  This parameter is OPTIONAL and may be
   2938     // omitted if the number of channels is one, provided that no
   2939     // additional parameters are needed.
   2940     size_t channels = 1;
   2941     if (codec_params.size() == 3) {
   2942       if (!GetValueFromString(line, codec_params[2], &channels, error)) {
   2943         return false;
   2944       }
   2945     }
   2946     int bitrate = 0;
   2947     // The default behavior for ISAC (bitrate == 0) in webrtcvoiceengine.cc
   2948     // (specifically FindWebRtcCodec) is bandwidth-adaptive variable bitrate.
   2949     // The bandwidth adaptation doesn't always work well, so this code
   2950     // sets a fixed target bitrate instead.
   2951     if (_stricmp(encoding_name.c_str(), kIsacCodecName) == 0) {
   2952       if (clock_rate <= 16000) {
   2953         bitrate = kIsacWbDefaultRate;
   2954       } else {
   2955         bitrate = kIsacSwbDefaultRate;
   2956       }
   2957     }
   2958     AudioContentDescription* audio_desc =
   2959         static_cast<AudioContentDescription*>(media_desc);
   2960     UpdateCodec(payload_type, encoding_name, clock_rate, bitrate, channels,
   2961                 preference, audio_desc);
   2962   } else if (media_type == cricket::MEDIA_TYPE_DATA) {
   2963     DataContentDescription* data_desc =
   2964         static_cast<DataContentDescription*>(media_desc);
   2965     data_desc->AddCodec(cricket::DataCodec(payload_type, encoding_name,
   2966                                            preference));
   2967   }
   2968   return true;
   2969 }
   2970 
   2971 bool ParseFmtpParam(const std::string& line, std::string* parameter,
   2972                     std::string* value, SdpParseError* error) {
   2973   if (!rtc::tokenize_first(line, kSdpDelimiterEqual, parameter, value)) {
   2974     ParseFailed(line, "Unable to parse fmtp parameter. \'=\' missing.", error);
   2975     return false;
   2976   }
   2977   // a=fmtp:<payload_type> <param1>=<value1>; <param2>=<value2>; ...
   2978   return true;
   2979 }
   2980 
   2981 bool ParseFmtpAttributes(const std::string& line, const MediaType media_type,
   2982                          MediaContentDescription* media_desc,
   2983                          SdpParseError* error) {
   2984   if (media_type != cricket::MEDIA_TYPE_AUDIO &&
   2985       media_type != cricket::MEDIA_TYPE_VIDEO) {
   2986     return true;
   2987   }
   2988 
   2989   std::string line_payload;
   2990   std::string line_params;
   2991 
   2992   // RFC 5576
   2993   // a=fmtp:<format> <format specific parameters>
   2994   // At least two fields, whereas the second one is any of the optional
   2995   // parameters.
   2996   if (!rtc::tokenize_first(line.substr(kLinePrefixLength), kSdpDelimiterSpace,
   2997                            &line_payload, &line_params)) {
   2998     ParseFailedExpectMinFieldNum(line, 2, error);
   2999     return false;
   3000   }
   3001 
   3002   // Parse out the payload information.
   3003   std::string payload_type_str;
   3004   if (!GetValue(line_payload, kAttributeFmtp, &payload_type_str, error)) {
   3005     return false;
   3006   }
   3007 
   3008   int payload_type = 0;
   3009   if (!GetPayloadTypeFromString(line_payload, payload_type_str, &payload_type,
   3010                                 error)) {
   3011     return false;
   3012   }
   3013 
   3014   // Parse out format specific parameters.
   3015   std::vector<std::string> fields;
   3016   rtc::split(line_params, kSdpDelimiterSemicolon, &fields);
   3017 
   3018   cricket::CodecParameterMap codec_params;
   3019   for (auto& iter : fields) {
   3020     if (iter.find(kSdpDelimiterEqual) == std::string::npos) {
   3021       // Only fmtps with equals are currently supported. Other fmtp types
   3022       // should be ignored. Unknown fmtps do not constitute an error.
   3023       continue;
   3024     }
   3025 
   3026     std::string name;
   3027     std::string value;
   3028     if (!ParseFmtpParam(rtc::string_trim(iter), &name, &value, error)) {
   3029       return false;
   3030     }
   3031     codec_params[name] = value;
   3032   }
   3033 
   3034   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   3035     UpdateCodec<AudioContentDescription, cricket::AudioCodec>(
   3036         media_desc, payload_type, codec_params);
   3037   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   3038     UpdateCodec<VideoContentDescription, cricket::VideoCodec>(
   3039         media_desc, payload_type, codec_params);
   3040   }
   3041   return true;
   3042 }
   3043 
   3044 bool ParseRtcpFbAttribute(const std::string& line, const MediaType media_type,
   3045                           MediaContentDescription* media_desc,
   3046                           SdpParseError* error) {
   3047   if (media_type != cricket::MEDIA_TYPE_AUDIO &&
   3048       media_type != cricket::MEDIA_TYPE_VIDEO) {
   3049     return true;
   3050   }
   3051   std::vector<std::string> rtcp_fb_fields;
   3052   rtc::split(line.c_str(), kSdpDelimiterSpace, &rtcp_fb_fields);
   3053   if (rtcp_fb_fields.size() < 2) {
   3054     return ParseFailedGetValue(line, kAttributeRtcpFb, error);
   3055   }
   3056   std::string payload_type_string;
   3057   if (!GetValue(rtcp_fb_fields[0], kAttributeRtcpFb, &payload_type_string,
   3058                 error)) {
   3059     return false;
   3060   }
   3061   int payload_type = kWildcardPayloadType;
   3062   if (payload_type_string != "*") {
   3063     if (!GetPayloadTypeFromString(line, payload_type_string, &payload_type,
   3064                                   error)) {
   3065       return false;
   3066     }
   3067   }
   3068   std::string id = rtcp_fb_fields[1];
   3069   std::string param = "";
   3070   for (std::vector<std::string>::iterator iter = rtcp_fb_fields.begin() + 2;
   3071        iter != rtcp_fb_fields.end(); ++iter) {
   3072     param.append(*iter);
   3073   }
   3074   const cricket::FeedbackParam feedback_param(id, param);
   3075 
   3076   if (media_type == cricket::MEDIA_TYPE_AUDIO) {
   3077     UpdateCodec<AudioContentDescription, cricket::AudioCodec>(
   3078         media_desc, payload_type, feedback_param);
   3079   } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
   3080     UpdateCodec<VideoContentDescription, cricket::VideoCodec>(
   3081         media_desc, payload_type, feedback_param);
   3082   }
   3083   return true;
   3084 }
   3085 
   3086 }  // namespace webrtc
   3087