tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SdpAttribute.h (60862B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef _SDPATTRIBUTE_H_
      8 #define _SDPATTRIBUTE_H_
      9 
     10 #include <algorithm>
     11 #include <cctype>
     12 #include <cstring>
     13 #include <iomanip>
     14 #include <ostream>
     15 #include <sstream>
     16 #include <string>
     17 #include <vector>
     18 
     19 #include "common/EncodingConstraints.h"
     20 #include "mozilla/Assertions.h"
     21 #include "mozilla/Maybe.h"
     22 #include "mozilla/UniquePtr.h"
     23 #include "nsString.h"
     24 #include "sdp/SdpEnum.h"
     25 
     26 namespace mozilla {
     27 
     28 /**
     29 * Base class for SDP attributes
     30 */
     31 class SdpAttribute {
     32 public:
     33  enum AttributeType {
     34    kFirstAttribute = 0,
     35    kBundleOnlyAttribute = 0,
     36    kCandidateAttribute,
     37    kConnectionAttribute,
     38    kDirectionAttribute,
     39    kDtlsMessageAttribute,
     40    kEndOfCandidatesAttribute,
     41    kExtmapAttribute,
     42    kExtmapAllowMixedAttribute,
     43    kFingerprintAttribute,
     44    kFmtpAttribute,
     45    kGroupAttribute,
     46    kIceLiteAttribute,
     47    kIceMismatchAttribute,
     48    kIceOptionsAttribute,
     49    kIcePwdAttribute,
     50    kIceUfragAttribute,
     51    kIdentityAttribute,
     52    kImageattrAttribute,
     53    kLabelAttribute,
     54    kMaxptimeAttribute,
     55    kMidAttribute,
     56    kMsidAttribute,
     57    kMsidSemanticAttribute,
     58    kPtimeAttribute,
     59    kRemoteCandidatesAttribute,
     60    kRidAttribute,
     61    kRtcpAttribute,
     62    kRtcpFbAttribute,
     63    kRtcpMuxAttribute,
     64    kRtcpRsizeAttribute,
     65    kRtpmapAttribute,
     66    kSctpmapAttribute,
     67    kSetupAttribute,
     68    kSimulcastAttribute,
     69    kSsrcAttribute,
     70    kSsrcGroupAttribute,
     71    kSctpPortAttribute,
     72    kMaxMessageSizeAttribute,
     73    kLastAttribute = kMaxMessageSizeAttribute
     74  };
     75 
     76  explicit SdpAttribute(AttributeType type) : mType(type) {}
     77  virtual ~SdpAttribute() = default;
     78 
     79  virtual SdpAttribute* Clone() const = 0;
     80 
     81  AttributeType GetType() const { return mType; }
     82 
     83  virtual void Serialize(std::ostream&) const = 0;
     84 
     85  static bool IsAllowedAtSessionLevel(AttributeType type);
     86  static bool IsAllowedAtMediaLevel(AttributeType type);
     87  static const std::string GetAttributeTypeString(AttributeType type);
     88 
     89 protected:
     90  AttributeType mType;
     91 };
     92 
     93 inline std::ostream& operator<<(std::ostream& os, const SdpAttribute& attr) {
     94  attr.Serialize(os);
     95  return os;
     96 }
     97 
     98 inline std::ostream& operator<<(std::ostream& os,
     99                                const SdpAttribute::AttributeType type) {
    100  os << SdpAttribute::GetAttributeTypeString(type);
    101  return os;
    102 }
    103 
    104 ///////////////////////////////////////////////////////////////////////////
    105 // a=candidate, RFC5245
    106 //-------------------------------------------------------------------------
    107 //
    108 // candidate-attribute   = "candidate" ":" foundation SP component-id SP
    109 //                          transport SP
    110 //                          priority SP
    111 //                          connection-address SP     ;from RFC 4566
    112 //                          port         ;port from RFC 4566
    113 //                          SP cand-type
    114 //                          [SP rel-addr]
    115 //                          [SP rel-port]
    116 //                          *(SP extension-att-name SP
    117 //                               extension-att-value)
    118 // foundation            = 1*32ice-char
    119 // component-id          = 1*5DIGIT
    120 // transport             = "UDP" / transport-extension
    121 // transport-extension   = token              ; from RFC 3261
    122 // priority              = 1*10DIGIT
    123 // cand-type             = "typ" SP candidate-types
    124 // candidate-types       = "host" / "srflx" / "prflx" / "relay" / token
    125 // rel-addr              = "raddr" SP connection-address
    126 // rel-port              = "rport" SP port
    127 // extension-att-name    = byte-string    ;from RFC 4566
    128 // extension-att-value   = byte-string
    129 // ice-char              = ALPHA / DIGIT / "+" / "/"
    130 
    131 // We use a SdpMultiStringAttribute for candidates
    132 
    133 ///////////////////////////////////////////////////////////////////////////
    134 // a=connection, RFC4145
    135 //-------------------------------------------------------------------------
    136 //         connection-attr        = "a=connection:" conn-value
    137 //         conn-value             = "new" / "existing"
    138 class SdpConnectionAttribute : public SdpAttribute {
    139 public:
    140  enum ConnValue { kNew, kExisting };
    141 
    142  explicit SdpConnectionAttribute(SdpConnectionAttribute::ConnValue value)
    143      : SdpAttribute(kConnectionAttribute), mValue(value) {}
    144 
    145  SdpAttribute* Clone() const override {
    146    return new SdpConnectionAttribute(*this);
    147  }
    148 
    149  virtual void Serialize(std::ostream& os) const override;
    150 
    151  ConnValue mValue;
    152 };
    153 
    154 inline std::ostream& operator<<(std::ostream& os,
    155                                SdpConnectionAttribute::ConnValue c) {
    156  switch (c) {
    157    case SdpConnectionAttribute::kNew:
    158      os << "new";
    159      break;
    160    case SdpConnectionAttribute::kExisting:
    161      os << "existing";
    162      break;
    163    default:
    164      MOZ_ASSERT(false);
    165      os << "?";
    166  }
    167  return os;
    168 }
    169 
    170 ///////////////////////////////////////////////////////////////////////////
    171 // a=sendrecv / a=sendonly / a=recvonly / a=inactive, RFC 4566
    172 //-------------------------------------------------------------------------
    173 class SdpDirectionAttribute : public SdpAttribute {
    174 public:
    175  enum Direction {
    176    kInactive = 0,
    177    kSendonly = sdp::kSend,
    178    kRecvonly = sdp::kRecv,
    179    kSendrecv = sdp::kSend | sdp::kRecv
    180  };
    181 
    182  explicit SdpDirectionAttribute(Direction value)
    183      : SdpAttribute(kDirectionAttribute), mValue(value) {}
    184 
    185  SdpAttribute* Clone() const override {
    186    return new SdpDirectionAttribute(*this);
    187  }
    188 
    189  virtual void Serialize(std::ostream& os) const override;
    190 
    191  Direction mValue;
    192 };
    193 
    194 inline std::ostream& operator<<(std::ostream& os,
    195                                SdpDirectionAttribute::Direction d) {
    196  switch (d) {
    197    case SdpDirectionAttribute::kSendonly:
    198      os << "sendonly";
    199      break;
    200    case SdpDirectionAttribute::kRecvonly:
    201      os << "recvonly";
    202      break;
    203    case SdpDirectionAttribute::kSendrecv:
    204      os << "sendrecv";
    205      break;
    206    case SdpDirectionAttribute::kInactive:
    207      os << "inactive";
    208      break;
    209    default:
    210      MOZ_ASSERT(false);
    211      os << "?";
    212  }
    213  return os;
    214 }
    215 
    216 inline SdpDirectionAttribute::Direction reverse(
    217    SdpDirectionAttribute::Direction d) {
    218  switch (d) {
    219    case SdpDirectionAttribute::Direction::kInactive:
    220      return SdpDirectionAttribute::Direction::kInactive;
    221    case SdpDirectionAttribute::Direction::kSendonly:
    222      return SdpDirectionAttribute::Direction::kRecvonly;
    223    case SdpDirectionAttribute::Direction::kRecvonly:
    224      return SdpDirectionAttribute::Direction::kSendonly;
    225    case SdpDirectionAttribute::Direction::kSendrecv:
    226      return SdpDirectionAttribute::Direction::kSendrecv;
    227  }
    228  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid direction!");
    229  MOZ_RELEASE_ASSERT(false);
    230 }
    231 
    232 inline SdpDirectionAttribute::Direction operator|(
    233    SdpDirectionAttribute::Direction d1, SdpDirectionAttribute::Direction d2) {
    234  return (SdpDirectionAttribute::Direction)((unsigned)d1 | (unsigned)d2);
    235 }
    236 
    237 inline SdpDirectionAttribute::Direction operator&(
    238    SdpDirectionAttribute::Direction d1, SdpDirectionAttribute::Direction d2) {
    239  return (SdpDirectionAttribute::Direction)((unsigned)d1 & (unsigned)d2);
    240 }
    241 
    242 inline SdpDirectionAttribute::Direction operator|=(
    243    SdpDirectionAttribute::Direction& d1, SdpDirectionAttribute::Direction d2) {
    244  d1 = d1 | d2;
    245  return d1;
    246 }
    247 
    248 inline SdpDirectionAttribute::Direction operator&=(
    249    SdpDirectionAttribute::Direction& d1, SdpDirectionAttribute::Direction d2) {
    250  d1 = d1 & d2;
    251  return d1;
    252 }
    253 
    254 ///////////////////////////////////////////////////////////////////////////
    255 // a=dtls-message, draft-rescorla-dtls-in-sdp
    256 //-------------------------------------------------------------------------
    257 //   attribute               =/   dtls-message-attribute
    258 //
    259 //   dtls-message-attribute  =    "dtls-message" ":" role SP value
    260 //
    261 //   role                    =    "client" / "server"
    262 //
    263 //   value                   =    1*(ALPHA / DIGIT / "+" / "/" / "=" )
    264 //                                ; base64 encoded message
    265 class SdpDtlsMessageAttribute : public SdpAttribute {
    266 public:
    267  enum Role { kClient, kServer };
    268 
    269  explicit SdpDtlsMessageAttribute(Role role, const std::string& value)
    270      : SdpAttribute(kDtlsMessageAttribute), mRole(role), mValue(value) {}
    271 
    272  // TODO: remove this, Bug 1469702
    273  explicit SdpDtlsMessageAttribute(const std::string& unparsed)
    274      : SdpAttribute(kDtlsMessageAttribute), mRole(kClient) {
    275    std::istringstream is(unparsed);
    276    std::string error;
    277    // We're not really worried about errors here if we don't parse;
    278    // this attribute is a pure optimization.
    279    Parse(is, &error);
    280  }
    281 
    282  SdpAttribute* Clone() const override {
    283    return new SdpDtlsMessageAttribute(*this);
    284  }
    285 
    286  virtual void Serialize(std::ostream& os) const override;
    287 
    288  // TODO: remove this, Bug 1469702
    289  bool Parse(std::istream& is, std::string* error);
    290 
    291  Role mRole;
    292  std::string mValue;
    293 };
    294 
    295 inline std::ostream& operator<<(std::ostream& os,
    296                                SdpDtlsMessageAttribute::Role r) {
    297  switch (r) {
    298    case SdpDtlsMessageAttribute::kClient:
    299      os << "client";
    300      break;
    301    case SdpDtlsMessageAttribute::kServer:
    302      os << "server";
    303      break;
    304    default:
    305      MOZ_ASSERT(false);
    306      os << "?";
    307  }
    308  return os;
    309 }
    310 
    311 ///////////////////////////////////////////////////////////////////////////
    312 // a=extmap, RFC5285
    313 //-------------------------------------------------------------------------
    314 // RFC5285
    315 //        extmap = mapentry SP extensionname [SP extensionattributes]
    316 //
    317 //        extensionname = URI
    318 //
    319 //        direction = "sendonly" / "recvonly" / "sendrecv" / "inactive"
    320 //
    321 //        mapentry = "extmap:" 1*5DIGIT ["/" direction]
    322 //
    323 //        extensionattributes = byte-string
    324 //
    325 //        URI = <Defined in RFC 3986>
    326 //
    327 //        byte-string = <Defined in RFC 4566>
    328 //
    329 //        SP = <Defined in RFC 5234>
    330 //
    331 //        DIGIT = <Defined in RFC 5234>
    332 class SdpExtmapAttributeList : public SdpAttribute {
    333 public:
    334  SdpExtmapAttributeList() : SdpAttribute(kExtmapAttribute) {}
    335 
    336  struct Extmap {
    337    uint16_t entry;
    338    SdpDirectionAttribute::Direction direction;
    339    bool direction_specified;
    340    std::string extensionname;
    341    std::string extensionattributes;
    342  };
    343 
    344  void PushEntry(uint16_t entry, SdpDirectionAttribute::Direction direction,
    345                 bool direction_specified, const std::string& extensionname,
    346                 const std::string& extensionattributes = "") {
    347    Extmap value = {entry, direction, direction_specified, extensionname,
    348                    extensionattributes};
    349    mExtmaps.push_back(value);
    350  }
    351 
    352  SdpAttribute* Clone() const override {
    353    return new SdpExtmapAttributeList(*this);
    354  }
    355 
    356  virtual void Serialize(std::ostream& os) const override;
    357 
    358  std::vector<Extmap> mExtmaps;
    359 };
    360 
    361 ///////////////////////////////////////////////////////////////////////////
    362 // a=fingerprint, RFC4572
    363 //-------------------------------------------------------------------------
    364 //   fingerprint-attribute  =  "fingerprint" ":" hash-func SP fingerprint
    365 //
    366 //   hash-func              =  "sha-1" / "sha-224" / "sha-256" /
    367 //                             "sha-384" / "sha-512" /
    368 //                             "md5" / "md2" / token
    369 //                             ; Additional hash functions can only come
    370 //                             ; from updates to RFC 3279
    371 //
    372 //   fingerprint            =  2UHEX *(":" 2UHEX)
    373 //                             ; Each byte in upper-case hex, separated
    374 //                             ; by colons.
    375 //
    376 //   UHEX                   =  DIGIT / %x41-46 ; A-F uppercase
    377 class SdpFingerprintAttributeList : public SdpAttribute {
    378 public:
    379  SdpFingerprintAttributeList() : SdpAttribute(kFingerprintAttribute) {}
    380 
    381  enum HashAlgorithm {
    382    kSha1,
    383    kSha224,
    384    kSha256,
    385    kSha384,
    386    kSha512,
    387    kMd5,
    388    kMd2,
    389    kUnknownAlgorithm
    390  };
    391 
    392  struct Fingerprint {
    393    HashAlgorithm hashFunc;
    394    std::vector<uint8_t> fingerprint;
    395  };
    396 
    397  // For use by application programmers. Enforces that it's a known and
    398  // reasonable algorithm.
    399  void PushEntry(std::string algorithm_str,
    400                 const std::vector<uint8_t>& fingerprint,
    401                 bool enforcePlausible = true) {
    402    std::transform(algorithm_str.begin(), algorithm_str.end(),
    403                   algorithm_str.begin(), ::tolower);
    404 
    405    SdpFingerprintAttributeList::HashAlgorithm algorithm =
    406        SdpFingerprintAttributeList::kUnknownAlgorithm;
    407 
    408    if (algorithm_str == "sha-1") {
    409      algorithm = SdpFingerprintAttributeList::kSha1;
    410    } else if (algorithm_str == "sha-224") {
    411      algorithm = SdpFingerprintAttributeList::kSha224;
    412    } else if (algorithm_str == "sha-256") {
    413      algorithm = SdpFingerprintAttributeList::kSha256;
    414    } else if (algorithm_str == "sha-384") {
    415      algorithm = SdpFingerprintAttributeList::kSha384;
    416    } else if (algorithm_str == "sha-512") {
    417      algorithm = SdpFingerprintAttributeList::kSha512;
    418    } else if (algorithm_str == "md5") {
    419      algorithm = SdpFingerprintAttributeList::kMd5;
    420    } else if (algorithm_str == "md2") {
    421      algorithm = SdpFingerprintAttributeList::kMd2;
    422    }
    423 
    424    if ((algorithm == SdpFingerprintAttributeList::kUnknownAlgorithm) ||
    425        fingerprint.empty()) {
    426      if (enforcePlausible) {
    427        MOZ_ASSERT(false, "Unknown fingerprint algorithm");
    428      } else {
    429        return;
    430      }
    431    }
    432 
    433    PushEntry(algorithm, fingerprint);
    434  }
    435 
    436  void PushEntry(HashAlgorithm hashFunc,
    437                 const std::vector<uint8_t>& fingerprint) {
    438    Fingerprint value = {hashFunc, fingerprint};
    439    mFingerprints.push_back(value);
    440  }
    441 
    442  SdpAttribute* Clone() const override {
    443    return new SdpFingerprintAttributeList(*this);
    444  }
    445 
    446  virtual void Serialize(std::ostream& os) const override;
    447 
    448  std::vector<Fingerprint> mFingerprints;
    449 
    450  static std::string FormatFingerprint(const std::vector<uint8_t>& fp);
    451  static std::vector<uint8_t> ParseFingerprint(const std::string& str);
    452 };
    453 
    454 inline nsLiteralCString ToString(SdpFingerprintAttributeList::HashAlgorithm a) {
    455  static constexpr nsLiteralCString Values[] = {
    456      "sha-1"_ns,   "sha-224"_ns, "sha-256"_ns, "sha-384"_ns,
    457      "sha-512"_ns, "md5"_ns,     "md2"_ns,
    458  };
    459  if (a < std::size(Values)) return Values[a];
    460  MOZ_ASSERT(false);
    461  return "?"_ns;
    462 }
    463 
    464 inline std::ostream& operator<<(std::ostream& os,
    465                                SdpFingerprintAttributeList::HashAlgorithm a) {
    466  return os << ToString(a);
    467 }
    468 
    469 ///////////////////////////////////////////////////////////////////////////
    470 // a=group, RFC5888
    471 //-------------------------------------------------------------------------
    472 //         group-attribute     = "a=group:" semantics
    473 //                               *(SP identification-tag)
    474 //         semantics           = "LS" / "FID" / semantics-extension
    475 //         semantics-extension = token
    476 //         identification-tag  = token
    477 class SdpGroupAttributeList : public SdpAttribute {
    478 public:
    479  SdpGroupAttributeList() : SdpAttribute(kGroupAttribute) {}
    480 
    481  enum Semantics {
    482    kLs,     // RFC5888
    483    kFid,    // RFC5888
    484    kSrf,    // RFC3524
    485    kAnat,   // RFC4091
    486    kFec,    // RFC5956
    487    kFecFr,  // RFC5956
    488    kCs,     // draft-mehta-rmt-flute-sdp-05
    489    kDdp,    // RFC5583
    490    kDup,    // RFC7104
    491    kBundle  // draft-ietf-mmusic-bundle
    492  };
    493 
    494  struct Group {
    495    Semantics semantics;
    496    std::vector<std::string> tags;
    497  };
    498 
    499  void PushEntry(Semantics semantics, const std::vector<std::string>& tags) {
    500    Group value = {semantics, tags};
    501    mGroups.push_back(value);
    502  }
    503 
    504  void RemoveMid(const std::string& mid) {
    505    for (auto i = mGroups.begin(); i != mGroups.end();) {
    506      auto tag = std::find(i->tags.begin(), i->tags.end(), mid);
    507      if (tag != i->tags.end()) {
    508        i->tags.erase(tag);
    509      }
    510 
    511      if (i->tags.empty()) {
    512        i = mGroups.erase(i);
    513      } else {
    514        ++i;
    515      }
    516    }
    517  }
    518 
    519  SdpAttribute* Clone() const override {
    520    return new SdpGroupAttributeList(*this);
    521  }
    522 
    523  virtual void Serialize(std::ostream& os) const override;
    524 
    525  std::vector<Group> mGroups;
    526 };
    527 
    528 inline std::ostream& operator<<(std::ostream& os,
    529                                SdpGroupAttributeList::Semantics s) {
    530  switch (s) {
    531    case SdpGroupAttributeList::kLs:
    532      os << "LS";
    533      break;
    534    case SdpGroupAttributeList::kFid:
    535      os << "FID";
    536      break;
    537    case SdpGroupAttributeList::kSrf:
    538      os << "SRF";
    539      break;
    540    case SdpGroupAttributeList::kAnat:
    541      os << "ANAT";
    542      break;
    543    case SdpGroupAttributeList::kFec:
    544      os << "FEC";
    545      break;
    546    case SdpGroupAttributeList::kFecFr:
    547      os << "FEC-FR";
    548      break;
    549    case SdpGroupAttributeList::kCs:
    550      os << "CS";
    551      break;
    552    case SdpGroupAttributeList::kDdp:
    553      os << "DDP";
    554      break;
    555    case SdpGroupAttributeList::kDup:
    556      os << "DUP";
    557      break;
    558    case SdpGroupAttributeList::kBundle:
    559      os << "BUNDLE";
    560      break;
    561    default:
    562      MOZ_ASSERT(false);
    563      os << "?";
    564  }
    565  return os;
    566 }
    567 
    568 ///////////////////////////////////////////////////////////////////////////
    569 // a=identity, draft-ietf-rtcweb-security-arch
    570 //-------------------------------------------------------------------------
    571 //   identity-attribute  = "identity:" identity-assertion
    572 //                         [ SP identity-extension
    573 //                           *(";" [ SP ] identity-extension) ]
    574 //   identity-assertion  = base64
    575 //   base64              = 1*(ALPHA / DIGIT / "+" / "/" / "=" )
    576 //   identity-extension  = extension-att-name [ "=" extension-att-value ]
    577 //   extension-att-name  = token
    578 //   extension-att-value = 1*(%x01-09 / %x0b-0c / %x0e-3a / %x3c-ff)
    579 //                         ; byte-string from [RFC4566] omitting ";"
    580 
    581 // We're just using an SdpStringAttribute for this right now
    582 #if 0
    583 class SdpIdentityAttribute : public SdpAttribute
    584 {
    585 public:
    586  explicit SdpIdentityAttribute(const std::string &assertion,
    587                                const std::vector<std::string> &extensions =
    588                                    std::vector<std::string>()) :
    589    SdpAttribute(kIdentityAttribute),
    590    mAssertion(assertion),
    591    mExtensions(extensions) {}
    592 
    593  virtual void Serialize(std::ostream& os) const override;
    594 
    595  std::string mAssertion;
    596  std::vector<std::string> mExtensions;
    597 }
    598 #endif
    599 
    600 ///////////////////////////////////////////////////////////////////////////
    601 // a=imageattr, RFC6236
    602 //-------------------------------------------------------------------------
    603 //     image-attr = "imageattr:" PT 1*2( 1*WSP ( "send" / "recv" )
    604 //                                       1*WSP attr-list )
    605 //     PT = 1*DIGIT / "*"
    606 //     attr-list = ( set *(1*WSP set) ) / "*"
    607 //       ;  WSP and DIGIT defined in [RFC5234]
    608 //
    609 //     set= "[" "x=" xyrange "," "y=" xyrange *( "," key-value ) "]"
    610 //                ; x is the horizontal image size range (pixel count)
    611 //                ; y is the vertical image size range (pixel count)
    612 //
    613 //     key-value = ( "sar=" srange )
    614 //               / ( "par=" prange )
    615 //               / ( "q=" qvalue )
    616 //                ; Key-value MAY be extended with other keyword
    617 //                ;  parameters.
    618 //                ; At most, one instance each of sar, par, or q
    619 //                ;  is allowed in a set.
    620 //                ;
    621 //                ; sar (sample aspect ratio) is the sample aspect ratio
    622 //                ;  associated with the set (optional, MAY be ignored)
    623 //                ; par (picture aspect ratio) is the allowed
    624 //                ;  ratio between the display's x and y physical
    625 //                ;  size (optional)
    626 //                ; q (optional, range [0.0..1.0], default value 0.5)
    627 //                ;  is the preference for the given set,
    628 //                ;  a higher value means a higher preference
    629 //
    630 //     onetonine = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
    631 //                ; Digit between 1 and 9
    632 //     xyvalue = onetonine *5DIGIT
    633 //                ; Digit between 1 and 9 that is
    634 //                ; followed by 0 to 5 other digits
    635 //     step = xyvalue
    636 //     xyrange = ( "[" xyvalue ":" [ step ":" ] xyvalue "]" )
    637 //                ; Range between a lower and an upper value
    638 //                ; with an optional step, default step = 1
    639 //                ; The rightmost occurrence of xyvalue MUST have a
    640 //                ; higher value than the leftmost occurrence.
    641 //             / ( "[" xyvalue 1*( "," xyvalue ) "]" )
    642 //                ; Discrete values separated by ','
    643 //             / ( xyvalue )
    644 //                ; A single value
    645 //     spvalue = ( "0" "." onetonine *3DIGIT )
    646 //                ; Values between 0.1000 and 0.9999
    647 //             / ( onetonine "." 1*4DIGIT )
    648 //                ; Values between 1.0000 and 9.9999
    649 //     srange =  ( "[" spvalue 1*( "," spvalue ) "]" )
    650 //                ; Discrete values separated by ','.
    651 //                ; Each occurrence of spvalue MUST be
    652 //                ; greater than the previous occurrence.
    653 //             / ( "[" spvalue "-" spvalue "]" )
    654 //                ; Range between a lower and an upper level (inclusive)
    655 //                ; The second occurrence of spvalue MUST have a higher
    656 //                ; value than the first
    657 //             / ( spvalue )
    658 //                ; A single value
    659 //
    660 //     prange =  ( "[" spvalue "-" spvalue "]" )
    661 //                ; Range between a lower and an upper level (inclusive)
    662 //                ; The second occurrence of spvalue MUST have a higher
    663 //                ; value than the first
    664 //
    665 //     qvalue  = ( "0" "." 1*2DIGIT )
    666 //             / ( "1" "." 1*2("0") )
    667 //                ; Values between 0.00 and 1.00
    668 //
    669 //  XXX TBD -- We don't use this yet, and it's a project unto itself.
    670 //
    671 
    672 class SdpImageattrAttributeList : public SdpAttribute {
    673 public:
    674  SdpImageattrAttributeList() : SdpAttribute(kImageattrAttribute) {}
    675 
    676  class XYRange {
    677   public:
    678    XYRange() : min(0), max(0), step(1) {}
    679    void Serialize(std::ostream& os) const;
    680    // TODO: Remove this Bug 1469702
    681    bool Parse(std::istream& is, std::string* error);
    682    // TODO: Remove this Bug 1469702
    683    bool ParseAfterBracket(std::istream& is, std::string* error);
    684    // TODO: Remove this Bug 1469702
    685    bool ParseAfterMin(std::istream& is, std::string* error);
    686    // TODO: Remove this Bug 1469702
    687    bool ParseDiscreteValues(std::istream& is, std::string* error);
    688    std::vector<uint32_t> discreteValues;
    689    // min/max are used iff discreteValues is empty
    690    uint32_t min;
    691    uint32_t max;
    692    uint32_t step;
    693  };
    694 
    695  class SRange {
    696   public:
    697    SRange() : min(0), max(0) {}
    698    void Serialize(std::ostream& os) const;
    699    // TODO: Remove this Bug 1469702
    700    bool Parse(std::istream& is, std::string* error);
    701    // TODO: Remove this Bug 1469702
    702    bool ParseAfterBracket(std::istream& is, std::string* error);
    703    // TODO: Remove this Bug 1469702
    704    bool ParseAfterMin(std::istream& is, std::string* error);
    705    // TODO: Remove this Bug 1469702
    706    bool ParseDiscreteValues(std::istream& is, std::string* error);
    707    bool IsSet() const { return !discreteValues.empty() || (min && max); }
    708    std::vector<float> discreteValues;
    709    // min/max are used iff discreteValues is empty
    710    float min;
    711    float max;
    712  };
    713 
    714  class PRange {
    715   public:
    716    PRange() : min(0), max(0) {}
    717    void Serialize(std::ostream& os) const;
    718    // TODO: Remove this Bug 1469702
    719    bool Parse(std::istream& is, std::string* error);
    720    bool IsSet() const { return min && max; }
    721    float min;
    722    float max;
    723  };
    724 
    725  class Set {
    726   public:
    727    Set() : qValue(-1) {}
    728    void Serialize(std::ostream& os) const;
    729    // TODO: Remove this Bug 1469702
    730    bool Parse(std::istream& is, std::string* error);
    731    XYRange xRange;
    732    XYRange yRange;
    733    SRange sRange;
    734    PRange pRange;
    735    float qValue;
    736  };
    737 
    738  class Imageattr {
    739   public:
    740    Imageattr() : sendAll(false), recvAll(false) {}
    741    void Serialize(std::ostream& os) const;
    742    // TODO: Remove this Bug 1469702
    743    bool Parse(std::istream& is, std::string* error);
    744    // TODO: Remove this Bug 1469702
    745    bool ParseSets(std::istream& is, std::string* error);
    746    // If not set, this means all payload types
    747    Maybe<uint16_t> pt;
    748    bool sendAll;
    749    std::vector<Set> sendSets;
    750    bool recvAll;
    751    std::vector<Set> recvSets;
    752  };
    753 
    754  SdpAttribute* Clone() const override {
    755    return new SdpImageattrAttributeList(*this);
    756  }
    757 
    758  virtual void Serialize(std::ostream& os) const override;
    759 
    760  // TODO: Remove this Bug 1469702
    761  bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);
    762 
    763  std::vector<Imageattr> mImageattrs;
    764 };
    765 
    766 ///////////////////////////////////////////////////////////////////////////
    767 // a=msid, draft-ietf-mmusic-msid
    768 //-------------------------------------------------------------------------
    769 //   msid-attr = "msid:" identifier [ SP appdata ]
    770 //   identifier = 1*64token-char ; see RFC 4566
    771 //   appdata = 1*64token-char  ; see RFC 4566
    772 class SdpMsidAttributeList : public SdpAttribute {
    773 public:
    774  SdpMsidAttributeList() : SdpAttribute(kMsidAttribute) {}
    775 
    776  struct Msid {
    777    std::string identifier;
    778    std::string appdata;
    779  };
    780 
    781  void PushEntry(const std::string& identifier,
    782                 const std::string& appdata = "") {
    783    Msid value = {identifier, appdata};
    784    mMsids.push_back(value);
    785  }
    786 
    787  SdpAttribute* Clone() const override {
    788    return new SdpMsidAttributeList(*this);
    789  }
    790 
    791  virtual void Serialize(std::ostream& os) const override;
    792 
    793  std::vector<Msid> mMsids;
    794 };
    795 
    796 ///////////////////////////////////////////////////////////////////////////
    797 // a=msid-semantic, draft-ietf-mmusic-msid
    798 //-------------------------------------------------------------------------
    799 //   msid-semantic-attr = "msid-semantic:" msid-semantic msid-list
    800 //   msid-semantic = token ; see RFC 4566
    801 //   msid-list = *(" " msid-id) / " *"
    802 class SdpMsidSemanticAttributeList : public SdpAttribute {
    803 public:
    804  SdpMsidSemanticAttributeList() : SdpAttribute(kMsidSemanticAttribute) {}
    805 
    806  struct MsidSemantic {
    807    // TODO: Once we have some more of these, we might want to make an enum
    808    std::string semantic;
    809    std::vector<std::string> msids;
    810  };
    811 
    812  void PushEntry(const std::string& semantic,
    813                 const std::vector<std::string>& msids) {
    814    MsidSemantic value = {semantic, msids};
    815    mMsidSemantics.push_back(value);
    816  }
    817 
    818  SdpAttribute* Clone() const override {
    819    return new SdpMsidSemanticAttributeList(*this);
    820  }
    821 
    822  virtual void Serialize(std::ostream& os) const override;
    823 
    824  std::vector<MsidSemantic> mMsidSemantics;
    825 };
    826 
    827 ///////////////////////////////////////////////////////////////////////////
    828 // a=remote-candiate, RFC5245
    829 //-------------------------------------------------------------------------
    830 //   remote-candidate-att = "remote-candidates" ":" remote-candidate
    831 //                           0*(SP remote-candidate)
    832 //   remote-candidate = component-ID SP connection-address SP port
    833 class SdpRemoteCandidatesAttribute : public SdpAttribute {
    834 public:
    835  struct Candidate {
    836    std::string id;
    837    std::string address;
    838    uint16_t port;
    839  };
    840 
    841  explicit SdpRemoteCandidatesAttribute(
    842      const std::vector<Candidate>& candidates)
    843      : SdpAttribute(kRemoteCandidatesAttribute), mCandidates(candidates) {}
    844 
    845  SdpAttribute* Clone() const override {
    846    return new SdpRemoteCandidatesAttribute(*this);
    847  }
    848 
    849  virtual void Serialize(std::ostream& os) const override;
    850 
    851  std::vector<Candidate> mCandidates;
    852 };
    853 
    854 /*
    855 a=rid, draft-pthatcher-mmusic-rid-01
    856 
    857   rid-syntax        = "a=rid:" rid-identifier SP rid-dir
    858                       [ rid-pt-param-list / rid-param-list ]
    859 
    860   rid-identifier    = 1*(alpha-numeric / "-" / "_")
    861 
    862   rid-dir           = "send" / "recv"
    863 
    864   rid-pt-param-list = SP rid-fmt-list *(";" rid-param)
    865 
    866   rid-param-list    = SP rid-param *(";" rid-param)
    867 
    868   rid-fmt-list      = "pt=" fmt *( "," fmt )
    869                        ; fmt defined in {{RFC4566}}
    870 
    871   rid-param         = rid-width-param
    872                       / rid-height-param
    873                       / rid-fps-param
    874                       / rid-fs-param
    875                       / rid-br-param
    876                       / rid-pps-param
    877                       / rid-depend-param
    878                       / rid-param-other
    879 
    880   rid-width-param   = "max-width" [ "=" int-param-val ]
    881 
    882   rid-height-param  = "max-height" [ "=" int-param-val ]
    883 
    884   rid-fps-param     = "max-fps" [ "=" int-param-val ]
    885 
    886   rid-fs-param      = "max-fs" [ "=" int-param-val ]
    887 
    888   rid-br-param      = "max-br" [ "=" int-param-val ]
    889 
    890   rid-pps-param     = "max-pps" [ "=" int-param-val ]
    891 
    892   rid-depend-param  = "depend=" rid-list
    893 
    894   rid-param-other   = 1*(alpha-numeric / "-") [ "=" param-val ]
    895 
    896   rid-list          = rid-identifier *( "," rid-identifier )
    897 
    898   int-param-val     = 1*DIGIT
    899 
    900   param-val         = *( %x20-58 / %x60-7E )
    901                       ; Any printable character except semicolon
    902 */
    903 class SdpRidAttributeList : public SdpAttribute {
    904 public:
    905  explicit SdpRidAttributeList() : SdpAttribute(kRidAttribute) {}
    906 
    907  struct Rid {
    908    Rid() : direction(sdp::kSend) {}
    909 
    910    // Remove this function. See Bug 1469702
    911    bool Parse(std::istream& is, std::string* error);
    912    // Remove this function. See Bug 1469702
    913    bool ParseParameters(std::istream& is, std::string* error);
    914    // Remove this function. See Bug 1469702
    915    bool ParseDepend(std::istream& is, std::string* error);
    916    // Remove this function. See Bug 1469702
    917    bool ParseFormats(std::istream& is, std::string* error);
    918 
    919    void Serialize(std::ostream& os) const;
    920    void SerializeParameters(std::ostream& os) const;
    921    bool HasFormat(const std::string& format) const;
    922    bool HasParameters() const {
    923      return !formats.empty() || constraints.maxWidth ||
    924             constraints.maxHeight || constraints.maxFps || constraints.maxFs ||
    925             constraints.maxBr || constraints.maxPps || !dependIds.empty();
    926    }
    927 
    928    std::string id;
    929    sdp::Direction direction;
    930    std::vector<uint16_t> formats;  // Empty implies all
    931    VideoEncodingConstraints constraints;
    932    std::vector<std::string> dependIds;
    933  };
    934 
    935  SdpAttribute* Clone() const override {
    936    return new SdpRidAttributeList(*this);
    937  }
    938 
    939  static bool CheckRidValidity(const std::string& aRid, std::string* aError);
    940  static size_t kMaxRidLength;
    941 
    942  virtual void Serialize(std::ostream& os) const override;
    943 
    944  // Remove this function. See Bug 1469702
    945  bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);
    946 
    947  void PushEntry(const std::string& id, sdp::Direction dir,
    948                 const std::vector<uint16_t>& formats,
    949                 const VideoEncodingConstraints& constraints,
    950                 const std::vector<std::string>& dependIds);
    951 
    952  std::vector<Rid> mRids;
    953 };
    954 
    955 ///////////////////////////////////////////////////////////////////////////
    956 // a=rtcp, RFC3605
    957 //-------------------------------------------------------------------------
    958 //   rtcp-attribute =  "a=rtcp:" port  [nettype space addrtype space
    959 //                         connection-address] CRLF
    960 class SdpRtcpAttribute : public SdpAttribute {
    961 public:
    962  explicit SdpRtcpAttribute(uint16_t port)
    963      : SdpAttribute(kRtcpAttribute),
    964        mPort(port),
    965        mNetType(sdp::kNetTypeNone),
    966        mAddrType(sdp::kAddrTypeNone) {}
    967 
    968  SdpRtcpAttribute(uint16_t port, sdp::NetType netType, sdp::AddrType addrType,
    969                   const std::string& address)
    970      : SdpAttribute(kRtcpAttribute),
    971        mPort(port),
    972        mNetType(netType),
    973        mAddrType(addrType),
    974        mAddress(address) {
    975    MOZ_ASSERT(netType != sdp::kNetTypeNone);
    976    MOZ_ASSERT(addrType != sdp::kAddrTypeNone);
    977    MOZ_ASSERT(!address.empty());
    978  }
    979 
    980  SdpAttribute* Clone() const override { return new SdpRtcpAttribute(*this); }
    981 
    982  virtual void Serialize(std::ostream& os) const override;
    983 
    984  uint16_t mPort;
    985  sdp::NetType mNetType;
    986  sdp::AddrType mAddrType;
    987  std::string mAddress;
    988 };
    989 
    990 ///////////////////////////////////////////////////////////////////////////
    991 // a=rtcp-fb, RFC4585
    992 //-------------------------------------------------------------------------
    993 //    rtcp-fb-syntax = "a=rtcp-fb:" rtcp-fb-pt SP rtcp-fb-val CRLF
    994 //
    995 //    rtcp-fb-pt         = "*"   ; wildcard: applies to all formats
    996 //                       / fmt   ; as defined in SDP spec
    997 //
    998 //    rtcp-fb-val        = "ack" rtcp-fb-ack-param
    999 //                       / "nack" rtcp-fb-nack-param
   1000 //                       / "trr-int" SP 1*DIGIT
   1001 //                       / rtcp-fb-id rtcp-fb-param
   1002 //
   1003 //    rtcp-fb-id         = 1*(alpha-numeric / "-" / "_")
   1004 //
   1005 //    rtcp-fb-param      = SP "app" [SP byte-string]
   1006 //                       / SP token [SP byte-string]
   1007 //                       / ; empty
   1008 //
   1009 //    rtcp-fb-ack-param  = SP "rpsi"
   1010 //                       / SP "app" [SP byte-string]
   1011 //                       / SP token [SP byte-string]
   1012 //                       / ; empty
   1013 //
   1014 //    rtcp-fb-nack-param = SP "pli"
   1015 //                       / SP "sli"
   1016 //                       / SP "rpsi"
   1017 //                       / SP "app" [SP byte-string]
   1018 //                       / SP token [SP byte-string]
   1019 //                       / ; empty
   1020 //
   1021 class SdpRtcpFbAttributeList : public SdpAttribute {
   1022 public:
   1023  SdpRtcpFbAttributeList() : SdpAttribute(kRtcpFbAttribute) {}
   1024 
   1025  enum Type { kAck, kApp, kCcm, kNack, kTrrInt, kRemb, kTransportCC };
   1026 
   1027  static const char* pli;
   1028  static const char* sli;
   1029  static const char* rpsi;
   1030  static const char* app;
   1031 
   1032  static const char* fir;
   1033  static const char* tmmbr;
   1034  static const char* tstr;
   1035  static const char* vbcm;
   1036 
   1037  struct Feedback {
   1038    std::string pt;
   1039    Type type;
   1040    std::string parameter;
   1041    std::string extra;
   1042    // TODO(bug 1744307): Use =default here once it is supported
   1043    bool operator==(const Feedback& aOther) const {
   1044      return pt == aOther.pt && type == aOther.type &&
   1045             parameter == aOther.parameter && extra == aOther.extra;
   1046    }
   1047  };
   1048 
   1049  void PushEntry(const std::string& pt, Type type,
   1050                 const std::string& parameter = "",
   1051                 const std::string& extra = "") {
   1052    Feedback value = {pt, type, parameter, extra};
   1053    mFeedbacks.push_back(value);
   1054  }
   1055 
   1056  SdpAttribute* Clone() const override {
   1057    return new SdpRtcpFbAttributeList(*this);
   1058  }
   1059 
   1060  virtual void Serialize(std::ostream& os) const override;
   1061 
   1062  std::vector<Feedback> mFeedbacks;
   1063 };
   1064 
   1065 inline std::ostream& operator<<(std::ostream& os,
   1066                                SdpRtcpFbAttributeList::Type type) {
   1067  switch (type) {
   1068    case SdpRtcpFbAttributeList::kAck:
   1069      os << "ack";
   1070      break;
   1071    case SdpRtcpFbAttributeList::kApp:
   1072      os << "app";
   1073      break;
   1074    case SdpRtcpFbAttributeList::kCcm:
   1075      os << "ccm";
   1076      break;
   1077    case SdpRtcpFbAttributeList::kNack:
   1078      os << "nack";
   1079      break;
   1080    case SdpRtcpFbAttributeList::kTrrInt:
   1081      os << "trr-int";
   1082      break;
   1083    case SdpRtcpFbAttributeList::kRemb:
   1084      os << "goog-remb";
   1085      break;
   1086    case SdpRtcpFbAttributeList::kTransportCC:
   1087      os << "transport-cc";
   1088      break;
   1089    default:
   1090      MOZ_ASSERT(false);
   1091      os << "?";
   1092  }
   1093  return os;
   1094 }
   1095 
   1096 ///////////////////////////////////////////////////////////////////////////
   1097 // a=rtpmap, RFC4566
   1098 //-------------------------------------------------------------------------
   1099 // a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
   1100 class SdpRtpmapAttributeList : public SdpAttribute {
   1101 public:
   1102  SdpRtpmapAttributeList() : SdpAttribute(kRtpmapAttribute) {}
   1103 
   1104  // Minimal set to get going
   1105  enum CodecType {
   1106    kOpus,
   1107    kG722,
   1108    kPCMU,
   1109    kPCMA,
   1110    kVP8,
   1111    kVP9,
   1112    kiLBC,
   1113    kiSAC,
   1114    kH264,
   1115    kAV1,
   1116    kRed,
   1117    kUlpfec,
   1118    kTelephoneEvent,
   1119    kRtx,
   1120    kOtherCodec
   1121  };
   1122 
   1123  struct Rtpmap {
   1124    std::string pt;
   1125    CodecType codec;
   1126    std::string name;
   1127    uint32_t clock;
   1128    // Technically, this could mean something else in the future.
   1129    // In practice, that's probably not going to happen.
   1130    uint32_t channels;
   1131  };
   1132 
   1133  void PushEntry(const std::string& pt, CodecType codec,
   1134                 const std::string& name, uint32_t clock,
   1135                 uint32_t channels = 0) {
   1136    Rtpmap value = {pt, codec, name, clock, channels};
   1137    mRtpmaps.push_back(value);
   1138  }
   1139 
   1140  SdpAttribute* Clone() const override {
   1141    return new SdpRtpmapAttributeList(*this);
   1142  }
   1143 
   1144  virtual void Serialize(std::ostream& os) const override;
   1145 
   1146  bool HasEntry(const std::string& pt) const {
   1147    for (auto it = mRtpmaps.begin(); it != mRtpmaps.end(); ++it) {
   1148      if (it->pt == pt) {
   1149        return true;
   1150      }
   1151    }
   1152    return false;
   1153  }
   1154 
   1155  const Rtpmap& GetEntry(const std::string& pt) const {
   1156    for (auto it = mRtpmaps.begin(); it != mRtpmaps.end(); ++it) {
   1157      if (it->pt == pt) {
   1158        return *it;
   1159      }
   1160    }
   1161    MOZ_CRASH();
   1162  }
   1163 
   1164  std::vector<Rtpmap> mRtpmaps;
   1165 };
   1166 
   1167 inline std::ostream& operator<<(std::ostream& os,
   1168                                SdpRtpmapAttributeList::CodecType c) {
   1169  switch (c) {
   1170    case SdpRtpmapAttributeList::kOpus:
   1171      os << "opus";
   1172      break;
   1173    case SdpRtpmapAttributeList::kG722:
   1174      os << "G722";
   1175      break;
   1176    case SdpRtpmapAttributeList::kPCMU:
   1177      os << "PCMU";
   1178      break;
   1179    case SdpRtpmapAttributeList::kPCMA:
   1180      os << "PCMA";
   1181      break;
   1182    case SdpRtpmapAttributeList::kVP8:
   1183      os << "VP8";
   1184      break;
   1185    case SdpRtpmapAttributeList::kVP9:
   1186      os << "VP9";
   1187      break;
   1188    case SdpRtpmapAttributeList::kiLBC:
   1189      os << "iLBC";
   1190      break;
   1191    case SdpRtpmapAttributeList::kiSAC:
   1192      os << "iSAC";
   1193      break;
   1194    case SdpRtpmapAttributeList::kH264:
   1195      os << "H264";
   1196      break;
   1197    case SdpRtpmapAttributeList::kAV1:
   1198      os << "AV1";
   1199      break;
   1200    case SdpRtpmapAttributeList::kRed:
   1201      os << "red";
   1202      break;
   1203    case SdpRtpmapAttributeList::kUlpfec:
   1204      os << "ulpfec";
   1205      break;
   1206    case SdpRtpmapAttributeList::kTelephoneEvent:
   1207      os << "telephone-event";
   1208      break;
   1209    case SdpRtpmapAttributeList::kRtx:
   1210      os << "rtx";
   1211      break;
   1212    default:
   1213      MOZ_ASSERT(false);
   1214      os << "?";
   1215  }
   1216  return os;
   1217 }
   1218 
   1219 ///////////////////////////////////////////////////////////////////////////
   1220 // a=fmtp, RFC4566, RFC5576
   1221 //-------------------------------------------------------------------------
   1222 //       a=fmtp:<format> <format specific parameters>
   1223 //
   1224 class SdpFmtpAttributeList : public SdpAttribute {
   1225 public:
   1226  SdpFmtpAttributeList() : SdpAttribute(kFmtpAttribute) {}
   1227 
   1228  // Base class for format parameters
   1229  class Parameters {
   1230   public:
   1231    explicit Parameters(SdpRtpmapAttributeList::CodecType aCodec)
   1232        : codec_type(aCodec) {}
   1233 
   1234    virtual ~Parameters() = default;
   1235    virtual Parameters* Clone() const = 0;
   1236    virtual bool ShouldSerialize() const { return true; }
   1237    virtual void Serialize(std::ostream& os) const = 0;
   1238    virtual bool CompareEq(const Parameters& other) const = 0;
   1239 
   1240    bool operator==(const Parameters& other) const {
   1241      return codec_type == other.codec_type && CompareEq(other);
   1242    }
   1243    SdpRtpmapAttributeList::CodecType codec_type;
   1244  };
   1245 
   1246  class RedParameters : public Parameters {
   1247   public:
   1248    RedParameters() : Parameters(SdpRtpmapAttributeList::kRed) {}
   1249 
   1250    virtual Parameters* Clone() const override {
   1251      return new RedParameters(*this);
   1252    }
   1253 
   1254    virtual void Serialize(std::ostream& os) const override {
   1255      for (size_t i = 0; i < encodings.size(); ++i) {
   1256        os << (i != 0 ? "/" : "") << std::to_string(encodings[i]);
   1257      }
   1258    }
   1259 
   1260    virtual bool CompareEq(const Parameters& other) const override {
   1261      return encodings == static_cast<const RedParameters&>(other).encodings;
   1262    }
   1263 
   1264    std::vector<uint8_t> encodings;
   1265  };
   1266 
   1267  struct Av1Parameters : public Parameters {
   1268    // https://aomediacodec.github.io/av1-rtp-spec/#722-rid-restrictions-mapping-for-av1
   1269    Maybe<uint8_t> profile;
   1270    static constexpr uint8_t kDefaultProfile = 0;
   1271    Maybe<uint8_t> levelIdx;
   1272    static constexpr uint8_t kDefaultLevelIdx = 5;
   1273    Maybe<uint8_t> tier;
   1274    static constexpr uint8_t kDefaultTier = 0;
   1275 
   1276    Av1Parameters() : Parameters(SdpRtpmapAttributeList::kAV1) {}
   1277    Av1Parameters(const Av1Parameters&) = default;
   1278 
   1279    virtual ~Av1Parameters() = default;
   1280 
   1281    virtual Parameters* Clone() const override {
   1282      return new Av1Parameters(*this);
   1283    }
   1284 
   1285    // Returns the profile parameter if set, or the spec mandated default of 0.
   1286    auto profileValue() const -> uint8_t {
   1287      return profile.valueOr(kDefaultProfile);
   1288    }
   1289    // Returns the level-idx parameter if set, or the spec mandated default of
   1290    // 5.
   1291    auto levelIdxValue() const -> uint8_t {
   1292      return levelIdx.valueOr(kDefaultLevelIdx);
   1293    }
   1294    // Returns the tier parameter if set, or the spec mandated default of 0.
   1295    auto tierValue() const -> uint8_t { return tier.valueOr(kDefaultTier); }
   1296 
   1297    virtual bool ShouldSerialize() const override {
   1298      return profile.isSome() || levelIdx.isSome() || tier.isSome();
   1299    };
   1300 
   1301    virtual void Serialize(std::ostream& os) const override {
   1302      bool first = true;
   1303      profile.apply([&](const auto& profileV) {
   1304        os << "profile=" << static_cast<int>(profileV);
   1305        first = false;
   1306      });
   1307      levelIdx.apply([&](const auto& levelIdxV) {
   1308        os << (first ? "" : ";") << "level-idx=" << static_cast<int>(levelIdxV);
   1309        first = false;
   1310      });
   1311      tier.apply([&](const auto& tierV) {
   1312        os << (first ? "" : ";") << "tier=" << static_cast<int>(tierV);
   1313      });
   1314    }
   1315 
   1316    virtual bool CompareEq(const Parameters& aOther) const override {
   1317      return aOther.codec_type == codec_type &&
   1318             static_cast<const Av1Parameters&>(aOther).profile == profile &&
   1319             static_cast<const Av1Parameters&>(aOther).levelIdx == levelIdx &&
   1320             static_cast<const Av1Parameters&>(aOther).tier == tier;
   1321    }
   1322  };
   1323 
   1324  class RtxParameters : public Parameters {
   1325   public:
   1326    uint8_t apt = 255;  // Valid payload types are 0 - 127, use 255 to represent
   1327                        // unset value.
   1328    Maybe<uint32_t> rtx_time;
   1329 
   1330    RtxParameters() : Parameters(SdpRtpmapAttributeList::kRtx) {}
   1331 
   1332    virtual ~RtxParameters() = default;
   1333 
   1334    virtual Parameters* Clone() const override {
   1335      return new RtxParameters(*this);
   1336    }
   1337 
   1338    virtual void Serialize(std::ostream& os) const override {
   1339      if (apt <= 127) {
   1340        os << "apt=" << static_cast<uint32_t>(apt);
   1341        rtx_time.apply([&](const auto& time) { os << ";rtx-time=" << time; });
   1342      }
   1343    }
   1344 
   1345    virtual bool CompareEq(const Parameters& aOther) const override {
   1346      if (aOther.codec_type != codec_type) {
   1347        return false;
   1348      }
   1349      auto other = static_cast<const RtxParameters&>(aOther);
   1350      return other.apt == apt && other.rtx_time == rtx_time;
   1351    }
   1352  };
   1353 
   1354  class H264Parameters : public Parameters {
   1355   public:
   1356    // Baseline no constraints level 1
   1357    static const uint32_t kDefaultProfileLevelId = 0x42000A;
   1358 
   1359    H264Parameters()
   1360        : Parameters(SdpRtpmapAttributeList::kH264),
   1361          packetization_mode(0),
   1362          level_asymmetry_allowed(false),
   1363          profile_level_id(kDefaultProfileLevelId),
   1364          max_mbps(0),
   1365          max_fs(0),
   1366          max_cpb(0),
   1367          max_dpb(0),
   1368          max_br(0) {
   1369      memset(sprop_parameter_sets, 0, sizeof(sprop_parameter_sets));
   1370    }
   1371 
   1372    virtual Parameters* Clone() const override {
   1373      return new H264Parameters(*this);
   1374    }
   1375 
   1376    virtual void Serialize(std::ostream& os) const override {
   1377      // Note: don't move this, since having an unconditional param up top
   1378      // lets us avoid a whole bunch of conditional streaming of ';' below
   1379      os << "profile-level-id=" << std::hex << std::setfill('0') << std::setw(6)
   1380         << profile_level_id << std::dec << std::setfill(' ');
   1381 
   1382      os << ";level-asymmetry-allowed=" << (level_asymmetry_allowed ? 1 : 0);
   1383 
   1384      if (strlen(sprop_parameter_sets)) {
   1385        os << ";sprop-parameter-sets=" << sprop_parameter_sets;
   1386      }
   1387 
   1388      if (packetization_mode != 0) {
   1389        os << ";packetization-mode=" << packetization_mode;
   1390      }
   1391 
   1392      if (max_mbps != 0) {
   1393        os << ";max-mbps=" << max_mbps;
   1394      }
   1395 
   1396      if (max_fs != 0) {
   1397        os << ";max-fs=" << max_fs;
   1398      }
   1399 
   1400      if (max_cpb != 0) {
   1401        os << ";max-cpb=" << max_cpb;
   1402      }
   1403 
   1404      if (max_dpb != 0) {
   1405        os << ";max-dpb=" << max_dpb;
   1406      }
   1407 
   1408      if (max_br != 0) {
   1409        os << ";max-br=" << max_br;
   1410      }
   1411    }
   1412 
   1413    virtual bool CompareEq(const Parameters& other) const override {
   1414      const auto& otherH264 = static_cast<const H264Parameters&>(other);
   1415 
   1416      // sprop is not comapred here as it does not get parsed in the rsdparsa
   1417      return packetization_mode == otherH264.packetization_mode &&
   1418             level_asymmetry_allowed == otherH264.level_asymmetry_allowed &&
   1419             profile_level_id == otherH264.profile_level_id &&
   1420             max_mbps == otherH264.max_mbps && max_fs == otherH264.max_fs &&
   1421             max_cpb == otherH264.max_cpb && max_dpb == otherH264.max_dpb &&
   1422             max_br == otherH264.max_br;
   1423    }
   1424 
   1425    static const size_t max_sprop_len = 128;
   1426    char sprop_parameter_sets[max_sprop_len];
   1427    unsigned int packetization_mode;
   1428    bool level_asymmetry_allowed;
   1429    unsigned int profile_level_id;
   1430    unsigned int max_mbps;
   1431    unsigned int max_fs;
   1432    unsigned int max_cpb;
   1433    unsigned int max_dpb;
   1434    unsigned int max_br;
   1435  };
   1436 
   1437  // Also used for VP9 since they share parameters
   1438  class VP8Parameters : public Parameters {
   1439   public:
   1440    explicit VP8Parameters(SdpRtpmapAttributeList::CodecType type)
   1441        : Parameters(type), max_fs(0), max_fr(0) {}
   1442 
   1443    virtual Parameters* Clone() const override {
   1444      return new VP8Parameters(*this);
   1445    }
   1446 
   1447    virtual void Serialize(std::ostream& os) const override {
   1448      // draft-ietf-payload-vp8-11 says these are mandatory, upper layer
   1449      // needs to ensure they're set properly.
   1450      os << "max-fs=" << max_fs;
   1451      os << ";max-fr=" << max_fr;
   1452    }
   1453 
   1454    virtual bool CompareEq(const Parameters& other) const override {
   1455      const auto& otherVP8 = static_cast<const VP8Parameters&>(other);
   1456 
   1457      return max_fs == otherVP8.max_fs && max_fr == otherVP8.max_fr;
   1458    }
   1459 
   1460    unsigned int max_fs;
   1461    unsigned int max_fr;
   1462  };
   1463 
   1464  class OpusParameters : public Parameters {
   1465   public:
   1466    enum {
   1467      kDefaultMaxPlaybackRate = 48000,
   1468      kDefaultStereo = 0,
   1469      kDefaultUseInBandFec = 0,
   1470      kDefaultMaxAverageBitrate = 0,
   1471      kDefaultUseDTX = 0,
   1472      kDefaultFrameSize = 0,
   1473      kDefaultMinFrameSize = 0,
   1474      kDefaultMaxFrameSize = 0,
   1475      kDefaultUseCbr = 0
   1476    };
   1477    OpusParameters()
   1478        : Parameters(SdpRtpmapAttributeList::kOpus),
   1479          maxplaybackrate(kDefaultMaxPlaybackRate),
   1480          stereo(kDefaultStereo),
   1481          useInBandFec(kDefaultUseInBandFec),
   1482          maxAverageBitrate(kDefaultMaxAverageBitrate),
   1483          useDTX(kDefaultUseDTX),
   1484          frameSizeMs(kDefaultFrameSize),
   1485          minFrameSizeMs(kDefaultMinFrameSize),
   1486          maxFrameSizeMs(kDefaultMaxFrameSize),
   1487          useCbr(kDefaultUseCbr) {}
   1488 
   1489    Parameters* Clone() const override { return new OpusParameters(*this); }
   1490 
   1491    void Serialize(std::ostream& os) const override {
   1492      os << "maxplaybackrate=" << maxplaybackrate << ";stereo=" << stereo
   1493         << ";useinbandfec=" << useInBandFec;
   1494 
   1495      if (useDTX) {
   1496        os << ";usedtx=1";
   1497      }
   1498      if (maxAverageBitrate) {
   1499        os << ";maxaveragebitrate=" << maxAverageBitrate;
   1500      }
   1501      if (frameSizeMs) {
   1502        os << ";ptime=" << frameSizeMs;
   1503      }
   1504      if (minFrameSizeMs) {
   1505        os << ";minptime=" << minFrameSizeMs;
   1506      }
   1507      if (maxFrameSizeMs) {
   1508        os << ";maxptime=" << maxFrameSizeMs;
   1509      }
   1510      if (useCbr) {
   1511        os << ";cbr=1";
   1512      }
   1513    }
   1514 
   1515    virtual bool CompareEq(const Parameters& other) const override {
   1516      const auto& otherOpus = static_cast<const OpusParameters&>(other);
   1517 
   1518      bool maxplaybackrateIsEq = (maxplaybackrate == otherOpus.maxplaybackrate);
   1519 
   1520      // This is due to a bug in sipcc that causes maxplaybackrate to
   1521      // always be 0 if it appears in the fmtp
   1522      if (((maxplaybackrate == 0) && (otherOpus.maxplaybackrate != 0)) ||
   1523          ((maxplaybackrate != 0) && (otherOpus.maxplaybackrate == 0))) {
   1524        maxplaybackrateIsEq = true;
   1525      }
   1526 
   1527      return maxplaybackrateIsEq && stereo == otherOpus.stereo &&
   1528             useInBandFec == otherOpus.useInBandFec &&
   1529             maxAverageBitrate == otherOpus.maxAverageBitrate &&
   1530             useDTX == otherOpus.useDTX &&
   1531             frameSizeMs == otherOpus.frameSizeMs &&
   1532             minFrameSizeMs == otherOpus.minFrameSizeMs &&
   1533             maxFrameSizeMs == otherOpus.maxFrameSizeMs &&
   1534             useCbr == otherOpus.useCbr;
   1535    }
   1536 
   1537    unsigned int maxplaybackrate;
   1538    unsigned int stereo;
   1539    unsigned int useInBandFec;
   1540    uint32_t maxAverageBitrate;
   1541    bool useDTX;
   1542    uint32_t frameSizeMs;
   1543    uint32_t minFrameSizeMs;
   1544    uint32_t maxFrameSizeMs;
   1545    bool useCbr;
   1546  };
   1547 
   1548  class TelephoneEventParameters : public Parameters {
   1549   public:
   1550    TelephoneEventParameters()
   1551        : Parameters(SdpRtpmapAttributeList::kTelephoneEvent),
   1552          dtmfTones("0-15") {}
   1553 
   1554    virtual Parameters* Clone() const override {
   1555      return new TelephoneEventParameters(*this);
   1556    }
   1557 
   1558    void Serialize(std::ostream& os) const override { os << dtmfTones; }
   1559 
   1560    virtual bool CompareEq(const Parameters& other) const override {
   1561      return dtmfTones ==
   1562             static_cast<const TelephoneEventParameters&>(other).dtmfTones;
   1563    }
   1564 
   1565    std::string dtmfTones;
   1566  };
   1567 
   1568  class Fmtp {
   1569   public:
   1570    Fmtp(const std::string& aFormat, const Parameters& aParameters)
   1571        : format(aFormat), parameters(aParameters.Clone()) {}
   1572 
   1573    // TODO: Rip all of this out when we have move semantics in the stl.
   1574    Fmtp(const Fmtp& orig) { *this = orig; }
   1575 
   1576    Fmtp& operator=(const Fmtp& rhs) {
   1577      if (this != &rhs) {
   1578        format = rhs.format;
   1579        parameters.reset(rhs.parameters ? rhs.parameters->Clone() : nullptr);
   1580      }
   1581      return *this;
   1582    }
   1583 
   1584    bool operator==(const Fmtp& other) const {
   1585      return format == other.format && *parameters == *other.parameters;
   1586    }
   1587 
   1588    // The contract around these is as follows:
   1589    // * |parameters| is only set if we recognized the media type and had
   1590    //   a subclass of Parameters to represent that type of parameters
   1591    // * |parameters| is a best-effort representation; it might be missing
   1592    //   stuff
   1593    // * Parameters::codec_type tells you the concrete class, eg
   1594    //   kH264 -> H264Parameters
   1595    std::string format;
   1596    UniquePtr<Parameters> parameters;
   1597  };
   1598 
   1599  bool operator==(const SdpFmtpAttributeList& other) const;
   1600 
   1601  SdpAttribute* Clone() const override {
   1602    return new SdpFmtpAttributeList(*this);
   1603  }
   1604 
   1605  virtual void Serialize(std::ostream& os) const override;
   1606 
   1607  void PushEntry(const std::string& format, const Parameters& parameters) {
   1608    mFmtps.push_back(Fmtp(format, parameters));
   1609  }
   1610 
   1611  std::vector<Fmtp> mFmtps;
   1612 };
   1613 
   1614 ///////////////////////////////////////////////////////////////////////////
   1615 // a=sctpmap, draft-ietf-mmusic-sctp-sdp-05
   1616 //-------------------------------------------------------------------------
   1617 //      sctpmap-attr        =  "a=sctpmap:" sctpmap-number media-subtypes
   1618 // [streams]
   1619 //      sctpmap-number      =  1*DIGIT
   1620 //      protocol            =  labelstring
   1621 //        labelstring         =  text
   1622 //        text                =  byte-string
   1623 //      streams      =  1*DIGIT
   1624 //
   1625 // We're going to pretend that there are spaces where they make sense.
   1626 class SdpSctpmapAttributeList : public SdpAttribute {
   1627 public:
   1628  SdpSctpmapAttributeList() : SdpAttribute(kSctpmapAttribute) {}
   1629 
   1630  struct Sctpmap {
   1631    std::string pt;
   1632    std::string name;
   1633    uint32_t streams;
   1634  };
   1635 
   1636  void PushEntry(const std::string& pt, const std::string& name,
   1637                 uint32_t streams = 0) {
   1638    Sctpmap value = {pt, name, streams};
   1639    mSctpmaps.push_back(value);
   1640  }
   1641 
   1642  SdpAttribute* Clone() const override {
   1643    return new SdpSctpmapAttributeList(*this);
   1644  }
   1645 
   1646  virtual void Serialize(std::ostream& os) const override;
   1647 
   1648  bool HasEntry(const std::string& pt) const {
   1649    for (auto it = mSctpmaps.begin(); it != mSctpmaps.end(); ++it) {
   1650      if (it->pt == pt) {
   1651        return true;
   1652      }
   1653    }
   1654    return false;
   1655  }
   1656 
   1657  const Sctpmap& GetFirstEntry() const { return mSctpmaps[0]; }
   1658 
   1659  std::vector<Sctpmap> mSctpmaps;
   1660 };
   1661 
   1662 ///////////////////////////////////////////////////////////////////////////
   1663 // a=setup, RFC4145
   1664 //-------------------------------------------------------------------------
   1665 //       setup-attr           =  "a=setup:" role
   1666 //       role                 =  "active" / "passive" / "actpass" / "holdconn"
   1667 class SdpSetupAttribute : public SdpAttribute {
   1668 public:
   1669  enum Role { kActive, kPassive, kActpass, kHoldconn };
   1670 
   1671  explicit SdpSetupAttribute(Role role)
   1672      : SdpAttribute(kSetupAttribute), mRole(role) {}
   1673 
   1674  SdpAttribute* Clone() const override { return new SdpSetupAttribute(*this); }
   1675 
   1676  virtual void Serialize(std::ostream& os) const override;
   1677 
   1678  Role mRole;
   1679 };
   1680 
   1681 inline std::ostream& operator<<(std::ostream& os, SdpSetupAttribute::Role r) {
   1682  switch (r) {
   1683    case SdpSetupAttribute::kActive:
   1684      os << "active";
   1685      break;
   1686    case SdpSetupAttribute::kPassive:
   1687      os << "passive";
   1688      break;
   1689    case SdpSetupAttribute::kActpass:
   1690      os << "actpass";
   1691      break;
   1692    case SdpSetupAttribute::kHoldconn:
   1693      os << "holdconn";
   1694      break;
   1695    default:
   1696      MOZ_ASSERT(false);
   1697      os << "?";
   1698  }
   1699  return os;
   1700 }
   1701 
   1702 // Old draft-04
   1703 // sc-attr     = "a=simulcast:" 1*2( WSP sc-str-list ) [WSP sc-pause-list]
   1704 // sc-str-list = sc-dir WSP sc-id-type "=" sc-alt-list *( ";" sc-alt-list )
   1705 // sc-pause-list = "paused=" sc-alt-list
   1706 // sc-dir      = "send" / "recv"
   1707 // sc-id-type  = "pt" / "rid" / token
   1708 // sc-alt-list = sc-id *( "," sc-id )
   1709 // sc-id       = fmt / rid-identifier / token
   1710 // ; WSP defined in [RFC5234]
   1711 // ; fmt, token defined in [RFC4566]
   1712 // ; rid-identifier defined in [I-D.pthatcher-mmusic-rid]
   1713 //
   1714 // New draft 14, need to parse this for now, will eventually emit it
   1715 // sc-value     = ( sc-send [SP sc-recv] ) / ( sc-recv [SP sc-send] )
   1716 // sc-send      = %s"send" SP sc-str-list
   1717 // sc-recv      = %s"recv" SP sc-str-list
   1718 // sc-str-list  = sc-alt-list *( ";" sc-alt-list )
   1719 // sc-alt-list  = sc-id *( "," sc-id )
   1720 // sc-id-paused = "~"
   1721 // sc-id        = [sc-id-paused] rid-id
   1722 // ; SP defined in [RFC5234]
   1723 // ; rid-id defined in [I-D.ietf-mmusic-rid]
   1724 
   1725 class SdpSimulcastAttribute : public SdpAttribute {
   1726 public:
   1727  SdpSimulcastAttribute() : SdpAttribute(kSimulcastAttribute) {}
   1728 
   1729  SdpAttribute* Clone() const override {
   1730    return new SdpSimulcastAttribute(*this);
   1731  }
   1732 
   1733  void Serialize(std::ostream& os) const override;
   1734  bool Parse(std::istream& is, std::string* error);
   1735 
   1736  class Encoding {
   1737   public:
   1738    Encoding(const std::string& aRid, bool aPaused)
   1739        : rid(aRid), paused(aPaused) {}
   1740    std::string rid;
   1741    bool paused = false;
   1742  };
   1743 
   1744  class Version {
   1745   public:
   1746    void Serialize(std::ostream& os) const;
   1747    bool IsSet() const { return !choices.empty(); }
   1748    bool Parse(std::istream& is, std::string* error);
   1749 
   1750    std::vector<Encoding> choices;
   1751  };
   1752 
   1753  class Versions : public std::vector<Version> {
   1754   public:
   1755    void Serialize(std::ostream& os) const;
   1756    bool IsSet() const {
   1757      if (empty()) {
   1758        return false;
   1759      }
   1760 
   1761      for (const Version& version : *this) {
   1762        if (version.IsSet()) {
   1763          return true;
   1764        }
   1765      }
   1766 
   1767      return false;
   1768    }
   1769 
   1770    bool Parse(std::istream& is, std::string* error);
   1771  };
   1772 
   1773  Versions sendVersions;
   1774  Versions recvVersions;
   1775 };
   1776 
   1777 ///////////////////////////////////////////////////////////////////////////
   1778 // a=ssrc, RFC5576
   1779 //-------------------------------------------------------------------------
   1780 // ssrc-attr = "ssrc:" ssrc-id SP attribute
   1781 // ; The base definition of "attribute" is in RFC 4566.
   1782 // ; (It is the content of "a=" lines.)
   1783 //
   1784 // ssrc-id = integer ; 0 .. 2**32 - 1
   1785 //-------------------------------------------------------------------------
   1786 // TODO -- In the future, it might be nice if we ran a parse on the
   1787 // attribute section of this so that we could interpret it semantically.
   1788 // For WebRTC, the key use case for a=ssrc is assocaiting SSRCs with
   1789 // media sections, and we're not really going to care about the attribute
   1790 // itself. So we're just going to store it as a string for the time being.
   1791 // Issue 187.
   1792 class SdpSsrcAttributeList : public SdpAttribute {
   1793 public:
   1794  SdpSsrcAttributeList() : SdpAttribute(kSsrcAttribute) {}
   1795 
   1796  struct Ssrc {
   1797    uint32_t ssrc;
   1798    std::string attribute;
   1799  };
   1800 
   1801  void PushEntry(uint32_t ssrc, const std::string& attribute) {
   1802    Ssrc value = {ssrc, attribute};
   1803    mSsrcs.push_back(value);
   1804  }
   1805 
   1806  SdpAttribute* Clone() const override {
   1807    return new SdpSsrcAttributeList(*this);
   1808  }
   1809 
   1810  virtual void Serialize(std::ostream& os) const override;
   1811 
   1812  std::vector<Ssrc> mSsrcs;
   1813 };
   1814 
   1815 ///////////////////////////////////////////////////////////////////////////
   1816 // a=ssrc-group, RFC5576
   1817 //-------------------------------------------------------------------------
   1818 // ssrc-group-attr = "ssrc-group:" semantics *(SP ssrc-id)
   1819 //
   1820 // semantics       = "FEC" / "FID" / token
   1821 //
   1822 // ssrc-id = integer ; 0 .. 2**32 - 1
   1823 class SdpSsrcGroupAttributeList : public SdpAttribute {
   1824 public:
   1825  enum Semantics {
   1826    kFec,    // RFC5576
   1827    kFid,    // RFC5576
   1828    kFecFr,  // RFC5956
   1829    kDup,    // RFC7104
   1830    kSim     // non-standard, used by hangouts
   1831  };
   1832 
   1833  struct SsrcGroup {
   1834    Semantics semantics;
   1835    std::vector<uint32_t> ssrcs;
   1836  };
   1837 
   1838  SdpSsrcGroupAttributeList() : SdpAttribute(kSsrcGroupAttribute) {}
   1839 
   1840  void PushEntry(Semantics semantics, const std::vector<uint32_t>& ssrcs) {
   1841    SsrcGroup value = {semantics, ssrcs};
   1842    mSsrcGroups.push_back(value);
   1843  }
   1844 
   1845  SdpAttribute* Clone() const override {
   1846    return new SdpSsrcGroupAttributeList(*this);
   1847  }
   1848 
   1849  virtual void Serialize(std::ostream& os) const override;
   1850 
   1851  std::vector<SsrcGroup> mSsrcGroups;
   1852 };
   1853 
   1854 inline std::ostream& operator<<(std::ostream& os,
   1855                                SdpSsrcGroupAttributeList::Semantics s) {
   1856  switch (s) {
   1857    case SdpSsrcGroupAttributeList::kFec:
   1858      os << "FEC";
   1859      break;
   1860    case SdpSsrcGroupAttributeList::kFid:
   1861      os << "FID";
   1862      break;
   1863    case SdpSsrcGroupAttributeList::kFecFr:
   1864      os << "FEC-FR";
   1865      break;
   1866    case SdpSsrcGroupAttributeList::kDup:
   1867      os << "DUP";
   1868      break;
   1869    case SdpSsrcGroupAttributeList::kSim:
   1870      os << "SIM";
   1871      break;
   1872    default:
   1873      MOZ_ASSERT(false);
   1874      os << "?";
   1875  }
   1876  return os;
   1877 }
   1878 
   1879 ///////////////////////////////////////////////////////////////////////////
   1880 class SdpMultiStringAttribute : public SdpAttribute {
   1881 public:
   1882  explicit SdpMultiStringAttribute(AttributeType type) : SdpAttribute(type) {}
   1883 
   1884  void PushEntry(const std::string& entry) { mValues.push_back(entry); }
   1885 
   1886  SdpAttribute* Clone() const override {
   1887    return new SdpMultiStringAttribute(*this);
   1888  }
   1889 
   1890  virtual void Serialize(std::ostream& os) const override;
   1891 
   1892  std::vector<std::string> mValues;
   1893 };
   1894 
   1895 // otherwise identical to SdpMultiStringAttribute, this is used for
   1896 // ice-options and other places where the value is serialized onto
   1897 // a single line with space separating tokens
   1898 class SdpOptionsAttribute : public SdpAttribute {
   1899 public:
   1900  explicit SdpOptionsAttribute(AttributeType type) : SdpAttribute(type) {}
   1901 
   1902  void PushEntry(const std::string& entry) { mValues.push_back(entry); }
   1903 
   1904  void Load(const std::string& value);
   1905 
   1906  SdpAttribute* Clone() const override {
   1907    return new SdpOptionsAttribute(*this);
   1908  }
   1909 
   1910  virtual void Serialize(std::ostream& os) const override;
   1911 
   1912  std::vector<std::string> mValues;
   1913 };
   1914 
   1915 // Used for attributes that take no value (eg; a=ice-lite)
   1916 class SdpFlagAttribute : public SdpAttribute {
   1917 public:
   1918  explicit SdpFlagAttribute(AttributeType type) : SdpAttribute(type) {}
   1919 
   1920  SdpAttribute* Clone() const override { return new SdpFlagAttribute(*this); }
   1921 
   1922  virtual void Serialize(std::ostream& os) const override;
   1923 };
   1924 
   1925 // Used for any other kind of single-valued attribute not otherwise specialized
   1926 class SdpStringAttribute : public SdpAttribute {
   1927 public:
   1928  explicit SdpStringAttribute(AttributeType type, const std::string& value)
   1929      : SdpAttribute(type), mValue(value) {}
   1930 
   1931  SdpAttribute* Clone() const override { return new SdpStringAttribute(*this); }
   1932 
   1933  virtual void Serialize(std::ostream& os) const override;
   1934 
   1935  std::string mValue;
   1936 };
   1937 
   1938 // Used for any purely (non-negative) numeric attribute
   1939 class SdpNumberAttribute : public SdpAttribute {
   1940 public:
   1941  explicit SdpNumberAttribute(AttributeType type, uint32_t value = 0)
   1942      : SdpAttribute(type), mValue(value) {}
   1943 
   1944  SdpAttribute* Clone() const override { return new SdpNumberAttribute(*this); }
   1945 
   1946  virtual void Serialize(std::ostream& os) const override;
   1947 
   1948  uint32_t mValue;
   1949 };
   1950 
   1951 }  // namespace mozilla
   1952 
   1953 #endif