LCOV - code coverage report
Current view: top level - media/webrtc/signaling/src/sdp - SdpAttribute.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 428 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 226 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13