Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/media/webrtc/sdp/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 59 kB image not shown  

Quelle  SdpAttribute.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef _SDPATTRIBUTE_H_
#define _SDPATTRIBUTE_H_

#include <algorithm>
#include <cctype>
#include <vector>
#include <ostream>
#include <sstream>
#include <cstring>
#include <iomanip>
#include <string>

#include "mozilla/UniquePtr.h"
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include "nsString.h"

#include "sdp/SdpEnum.h"
#include "common/EncodingConstraints.h"

namespace mozilla {

/**
 * Base class for SDP attributes
 */

class SdpAttribute {
 public:
  enum AttributeType {
    kFirstAttribute = 0,
    kBundleOnlyAttribute = 0,
    kCandidateAttribute,
    kConnectionAttribute,
    kDirectionAttribute,
    kDtlsMessageAttribute,
    kEndOfCandidatesAttribute,
    kExtmapAttribute,
    kFingerprintAttribute,
    kFmtpAttribute,
    kGroupAttribute,
    kIceLiteAttribute,
    kIceMismatchAttribute,
    kIceOptionsAttribute,
    kIcePwdAttribute,
    kIceUfragAttribute,
    kIdentityAttribute,
    kImageattrAttribute,
    kLabelAttribute,
    kMaxptimeAttribute,
    kMidAttribute,
    kMsidAttribute,
    kMsidSemanticAttribute,
    kPtimeAttribute,
    kRemoteCandidatesAttribute,
    kRidAttribute,
    kRtcpAttribute,
    kRtcpFbAttribute,
    kRtcpMuxAttribute,
    kRtcpRsizeAttribute,
    kRtpmapAttribute,
    kSctpmapAttribute,
    kSetupAttribute,
    kSimulcastAttribute,
    kSsrcAttribute,
    kSsrcGroupAttribute,
    kSctpPortAttribute,
    kMaxMessageSizeAttribute,
    kLastAttribute = kMaxMessageSizeAttribute
  };

  explicit SdpAttribute(AttributeType type) : mType(type) {}
  virtual ~SdpAttribute() = default;

  virtual SdpAttribute* Clone() const = 0;

  AttributeType GetType() const { return mType; }

  virtual void Serialize(std::ostream&) const = 0;

  static bool IsAllowedAtSessionLevel(AttributeType type);
  static bool IsAllowedAtMediaLevel(AttributeType type);
  static const std::string GetAttributeTypeString(AttributeType type);

 protected:
  AttributeType mType;
};

inline std::ostream& operator<<(std::ostream& os, const SdpAttribute& attr) {
  attr.Serialize(os);
  return os;
}

inline std::ostream& operator<<(std::ostream& os,
                                const SdpAttribute::AttributeType type) {
  os << SdpAttribute::GetAttributeTypeString(type);
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=candidate, RFC5245
//-------------------------------------------------------------------------
//
// candidate-attribute   = "candidate" ":" foundation SP component-id SP
//                          transport SP
//                          priority SP
//                          connection-address SP     ;from RFC 4566
//                          port         ;port from RFC 4566
//                          SP cand-type
//                          [SP rel-addr]
//                          [SP rel-port]
//                          *(SP extension-att-name SP
//                               extension-att-value)
// foundation            = 1*32ice-char
// component-id          = 1*5DIGIT
// transport             = "UDP" / transport-extension
// transport-extension   = token              ; from RFC 3261
// priority              = 1*10DIGIT
// cand-type             = "typ" SP candidate-types
// candidate-types       = "host" / "srflx" / "prflx" / "relay" / token
// rel-addr              = "raddr" SP connection-address
// rel-port              = "rport" SP port
// extension-att-name    = byte-string    ;from RFC 4566
// extension-att-value   = byte-string
// ice-char              = ALPHA / DIGIT / "+" / "/"

// We use a SdpMultiStringAttribute for candidates

///////////////////////////////////////////////////////////////////////////
// a=connection, RFC4145
//-------------------------------------------------------------------------
//         connection-attr        = "a=connection:" conn-value
//         conn-value             = "new" / "existing"
class SdpConnectionAttribute : public SdpAttribute {
 public:
  enum ConnValue { kNew, kExisting };

  explicit SdpConnectionAttribute(SdpConnectionAttribute::ConnValue value)
      : SdpAttribute(kConnectionAttribute), mValue(value) {}

  SdpAttribute* Clone() const override {
    return new SdpConnectionAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  ConnValue mValue;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpConnectionAttribute::ConnValue c) {
  switch (c) {
    case SdpConnectionAttribute::kNew:
      os << "new";
      break;
    case SdpConnectionAttribute::kExisting:
      os << "existing";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=sendrecv / a=sendonly / a=recvonly / a=inactive, RFC 4566
//-------------------------------------------------------------------------
class SdpDirectionAttribute : public SdpAttribute {
 public:
  enum Direction {
    kInactive = 0,
    kSendonly = sdp::kSend,
    kRecvonly = sdp::kRecv,
    kSendrecv = sdp::kSend | sdp::kRecv
  };

  explicit SdpDirectionAttribute(Direction value)
      : SdpAttribute(kDirectionAttribute), mValue(value) {}

  SdpAttribute* Clone() const override {
    return new SdpDirectionAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  Direction mValue;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpDirectionAttribute::Direction d) {
  switch (d) {
    case SdpDirectionAttribute::kSendonly:
      os << "sendonly";
      break;
    case SdpDirectionAttribute::kRecvonly:
      os << "recvonly";
      break;
    case SdpDirectionAttribute::kSendrecv:
      os << "sendrecv";
      break;
    case SdpDirectionAttribute::kInactive:
      os << "inactive";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

inline SdpDirectionAttribute::Direction reverse(
    SdpDirectionAttribute::Direction d) {
  switch (d) {
    case SdpDirectionAttribute::Direction::kInactive:
      return SdpDirectionAttribute::Direction::kInactive;
    case SdpDirectionAttribute::Direction::kSendonly:
      return SdpDirectionAttribute::Direction::kRecvonly;
    case SdpDirectionAttribute::Direction::kRecvonly:
      return SdpDirectionAttribute::Direction::kSendonly;
    case SdpDirectionAttribute::Direction::kSendrecv:
      return SdpDirectionAttribute::Direction::kSendrecv;
  }
  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid direction!");
  MOZ_RELEASE_ASSERT(false);
}

inline SdpDirectionAttribute::Direction operator|(
    SdpDirectionAttribute::Direction d1, SdpDirectionAttribute::Direction d2) {
  return (SdpDirectionAttribute::Direction)((unsigned)d1 | (unsigned)d2);
}

inline SdpDirectionAttribute::Direction operator&(
    SdpDirectionAttribute::Direction d1, SdpDirectionAttribute::Direction d2) {
  return (SdpDirectionAttribute::Direction)((unsigned)d1 & (unsigned)d2);
}

inline SdpDirectionAttribute::Direction operator|=(
    SdpDirectionAttribute::Direction& d1, SdpDirectionAttribute::Direction d2) {
  d1 = d1 | d2;
  return d1;
}

inline SdpDirectionAttribute::Direction operator&=(
    SdpDirectionAttribute::Direction& d1, SdpDirectionAttribute::Direction d2) {
  d1 = d1 & d2;
  return d1;
}

///////////////////////////////////////////////////////////////////////////
// a=dtls-message, draft-rescorla-dtls-in-sdp
//-------------------------------------------------------------------------
//   attribute               =/   dtls-message-attribute
//
//   dtls-message-attribute  =    "dtls-message" ":" role SP value
//
//   role                    =    "client" / "server"
//
//   value                   =    1*(ALPHA / DIGIT / "+" / "/" / "=" )
//                                ; base64 encoded message
class SdpDtlsMessageAttribute : public SdpAttribute {
 public:
  enum Role { kClient, kServer };

  explicit SdpDtlsMessageAttribute(Role role, const std::string& value)
      : SdpAttribute(kDtlsMessageAttribute), mRole(role), mValue(value) {}

  // TODO: remove this, Bug 1469702
  explicit SdpDtlsMessageAttribute(const std::string& unparsed)
      : SdpAttribute(kDtlsMessageAttribute), mRole(kClient) {
    std::istringstream is(unparsed);
    std::string error;
    // We're not really worried about errors here if we don't parse;
    // this attribute is a pure optimization.
    Parse(is, &error);
  }

  SdpAttribute* Clone() const override {
    return new SdpDtlsMessageAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  // TODO: remove this, Bug 1469702
  bool Parse(std::istream& is, std::string* error);

  Role mRole;
  std::string mValue;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpDtlsMessageAttribute::Role r) {
  switch (r) {
    case SdpDtlsMessageAttribute::kClient:
      os << "client";
      break;
    case SdpDtlsMessageAttribute::kServer:
      os << "server";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=extmap, RFC5285
//-------------------------------------------------------------------------
// RFC5285
//        extmap = mapentry SP extensionname [SP extensionattributes]
//
//        extensionname = URI
//
//        direction = "sendonly" / "recvonly" / "sendrecv" / "inactive"
//
//        mapentry = "extmap:" 1*5DIGIT ["/" direction]
//
//        extensionattributes = byte-string
//
//        URI = <Defined in RFC 3986>
//
//        byte-string = <Defined in RFC 4566>
//
//        SP = <Defined in RFC 5234>
//
//        DIGIT = <Defined in RFC 5234>
class SdpExtmapAttributeList : public SdpAttribute {
 public:
  SdpExtmapAttributeList() : SdpAttribute(kExtmapAttribute) {}

  struct Extmap {
    uint16_t entry;
    SdpDirectionAttribute::Direction direction;
    bool direction_specified;
    std::string extensionname;
    std::string extensionattributes;
  };

  void PushEntry(uint16_t entry, SdpDirectionAttribute::Direction direction,
                 bool direction_specified, const std::string& extensionname,
                 const std::string& extensionattributes = "") {
    Extmap value = {entry, direction, direction_specified, extensionname,
                    extensionattributes};
    mExtmaps.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpExtmapAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Extmap> mExtmaps;
};

///////////////////////////////////////////////////////////////////////////
// a=fingerprint, RFC4572
//-------------------------------------------------------------------------
//   fingerprint-attribute  =  "fingerprint" ":" hash-func SP fingerprint
//
//   hash-func              =  "sha-1" / "sha-224" / "sha-256" /
//                             "sha-384" / "sha-512" /
//                             "md5" / "md2" / token
//                             ; Additional hash functions can only come
//                             ; from updates to RFC 3279
//
//   fingerprint            =  2UHEX *(":" 2UHEX)
//                             ; Each byte in upper-case hex, separated
//                             ; by colons.
//
//   UHEX                   =  DIGIT / %x41-46 ; A-F uppercase
class SdpFingerprintAttributeList : public SdpAttribute {
 public:
  SdpFingerprintAttributeList() : SdpAttribute(kFingerprintAttribute) {}

  enum HashAlgorithm {
    kSha1,
    kSha224,
    kSha256,
    kSha384,
    kSha512,
    kMd5,
    kMd2,
    kUnknownAlgorithm
  };

  struct Fingerprint {
    HashAlgorithm hashFunc;
    std::vector<uint8_t> fingerprint;
  };

  // For use by application programmers. Enforces that it's a known and
  // reasonable algorithm.
  void PushEntry(std::string algorithm_str,
                 const std::vector<uint8_t>& fingerprint,
                 bool enforcePlausible = true) {
    std::transform(algorithm_str.begin(), algorithm_str.end(),
                   algorithm_str.begin(), ::tolower);

    SdpFingerprintAttributeList::HashAlgorithm algorithm =
        SdpFingerprintAttributeList::kUnknownAlgorithm;

    if (algorithm_str == "sha-1") {
      algorithm = SdpFingerprintAttributeList::kSha1;
    } else if (algorithm_str == "sha-224") {
      algorithm = SdpFingerprintAttributeList::kSha224;
    } else if (algorithm_str == "sha-256") {
      algorithm = SdpFingerprintAttributeList::kSha256;
    } else if (algorithm_str == "sha-384") {
      algorithm = SdpFingerprintAttributeList::kSha384;
    } else if (algorithm_str == "sha-512") {
      algorithm = SdpFingerprintAttributeList::kSha512;
    } else if (algorithm_str == "md5") {
      algorithm = SdpFingerprintAttributeList::kMd5;
    } else if (algorithm_str == "md2") {
      algorithm = SdpFingerprintAttributeList::kMd2;
    }

    if ((algorithm == SdpFingerprintAttributeList::kUnknownAlgorithm) ||
        fingerprint.empty()) {
      if (enforcePlausible) {
        MOZ_ASSERT(false"Unknown fingerprint algorithm");
      } else {
        return;
      }
    }

    PushEntry(algorithm, fingerprint);
  }

  void PushEntry(HashAlgorithm hashFunc,
                 const std::vector<uint8_t>& fingerprint) {
    Fingerprint value = {hashFunc, fingerprint};
    mFingerprints.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpFingerprintAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Fingerprint> mFingerprints;

  static std::string FormatFingerprint(const std::vector<uint8_t>& fp);
  static std::vector<uint8_t> ParseFingerprint(const std::string& str);
};

inline nsLiteralCString ToString(SdpFingerprintAttributeList::HashAlgorithm a) {
  static constexpr nsLiteralCString Values[] = {
      "sha-1"_ns,   "sha-224"_ns, "sha-256"_ns, "sha-384"_ns,
      "sha-512"_ns, "md5"_ns,     "md2"_ns,
  };
  if (a < std::size(Values)) return Values[a];
  MOZ_ASSERT(false);
  return "?"_ns;
}

inline std::ostream& operator<<(std::ostream& os,
                                SdpFingerprintAttributeList::HashAlgorithm a) {
  return os << ToString(a);
}

///////////////////////////////////////////////////////////////////////////
// a=group, RFC5888
//-------------------------------------------------------------------------
//         group-attribute     = "a=group:" semantics
//                               *(SP identification-tag)
//         semantics           = "LS" / "FID" / semantics-extension
//         semantics-extension = token
//         identification-tag  = token
class SdpGroupAttributeList : public SdpAttribute {
 public:
  SdpGroupAttributeList() : SdpAttribute(kGroupAttribute) {}

  enum Semantics {
    kLs,     // RFC5888
    kFid,    // RFC5888
    kSrf,    // RFC3524
    kAnat,   // RFC4091
    kFec,    // RFC5956
    kFecFr,  // RFC5956
    kCs,     // draft-mehta-rmt-flute-sdp-05
    kDdp,    // RFC5583
    kDup,    // RFC7104
    kBundle  // draft-ietf-mmusic-bundle
  };

  struct Group {
    Semantics semantics;
    std::vector<std::string> tags;
  };

  void PushEntry(Semantics semantics, const std::vector<std::string>& tags) {
    Group value = {semantics, tags};
    mGroups.push_back(value);
  }

  void RemoveMid(const std::string& mid) {
    for (auto i = mGroups.begin(); i != mGroups.end();) {
      auto tag = std::find(i->tags.begin(), i->tags.end(), mid);
      if (tag != i->tags.end()) {
        i->tags.erase(tag);
      }

      if (i->tags.empty()) {
        i = mGroups.erase(i);
      } else {
        ++i;
      }
    }
  }

  SdpAttribute* Clone() const override {
    return new SdpGroupAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Group> mGroups;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpGroupAttributeList::Semantics s) {
  switch (s) {
    case SdpGroupAttributeList::kLs:
      os << "LS";
      break;
    case SdpGroupAttributeList::kFid:
      os << "FID";
      break;
    case SdpGroupAttributeList::kSrf:
      os << "SRF";
      break;
    case SdpGroupAttributeList::kAnat:
      os << "ANAT";
      break;
    case SdpGroupAttributeList::kFec:
      os << "FEC";
      break;
    case SdpGroupAttributeList::kFecFr:
      os << "FEC-FR";
      break;
    case SdpGroupAttributeList::kCs:
      os << "CS";
      break;
    case SdpGroupAttributeList::kDdp:
      os << "DDP";
      break;
    case SdpGroupAttributeList::kDup:
      os << "DUP";
      break;
    case SdpGroupAttributeList::kBundle:
      os << "BUNDLE";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=identity, draft-ietf-rtcweb-security-arch
//-------------------------------------------------------------------------
//   identity-attribute  = "identity:" identity-assertion
//                         [ SP identity-extension
//                           *(";" [ SP ] identity-extension) ]
//   identity-assertion  = base64
//   base64              = 1*(ALPHA / DIGIT / "+" / "/" / "=" )
//   identity-extension  = extension-att-name [ "=" extension-att-value ]
//   extension-att-name  = token
//   extension-att-value = 1*(%x01-09 / %x0b-0c / %x0e-3a / %x3c-ff)
//                         ; byte-string from [RFC4566] omitting ";"

// We're just using an SdpStringAttribute for this right now
#if 0
class SdpIdentityAttribute : public SdpAttribute
{
public:
  explicit SdpIdentityAttribute(const std::string &assertion,
                                const std::vector<std::string> &extensions =
                                    std::vector<std::string>()) :
    SdpAttribute(kIdentityAttribute),
    mAssertion(assertion),
    mExtensions(extensions) {}

  virtual void Serialize(std::ostream& os) const override;

  std::string mAssertion;
  std::vector<std::string> mExtensions;
}
#endif

///////////////////////////////////////////////////////////////////////////
// a=imageattr, RFC6236
//-------------------------------------------------------------------------
//     image-attr = "imageattr:" PT 1*2( 1*WSP ( "send" / "recv" )
//                                       1*WSP attr-list )
//     PT = 1*DIGIT / "*"
//     attr-list = ( set *(1*WSP set) ) / "*"
//       ;  WSP and DIGIT defined in [RFC5234]
//
//     set= "[" "x=" xyrange "," "y=" xyrange *( "," key-value ) "]"
//                ; x is the horizontal image size range (pixel count)
//                ; y is the vertical image size range (pixel count)
//
//     key-value = ( "sar=" srange )
//               / ( "par=" prange )
//               / ( "q=" qvalue )
//                ; Key-value MAY be extended with other keyword
//                ;  parameters.
//                ; At most, one instance each of sar, par, or q
//                ;  is allowed in a set.
//                ;
//                ; sar (sample aspect ratio) is the sample aspect ratio
//                ;  associated with the set (optional, MAY be ignored)
//                ; par (picture aspect ratio) is the allowed
//                ;  ratio between the display's x and y physical
//                ;  size (optional)
//                ; q (optional, range [0.0..1.0], default value 0.5)
//                ;  is the preference for the given set,
//                ;  a higher value means a higher preference
//
//     onetonine = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
//                ; Digit between 1 and 9
//     xyvalue = onetonine *5DIGIT
//                ; Digit between 1 and 9 that is
//                ; followed by 0 to 5 other digits
//     step = xyvalue
//     xyrange = ( "[" xyvalue ":" [ step ":" ] xyvalue "]" )
//                ; Range between a lower and an upper value
//                ; with an optional step, default step = 1
//                ; The rightmost occurrence of xyvalue MUST have a
//                ; higher value than the leftmost occurrence.
//             / ( "[" xyvalue 1*( "," xyvalue ) "]" )
//                ; Discrete values separated by ','
//             / ( xyvalue )
//                ; A single value
//     spvalue = ( "0" "." onetonine *3DIGIT )
//                ; Values between 0.1000 and 0.9999
//             / ( onetonine "." 1*4DIGIT )
//                ; Values between 1.0000 and 9.9999
//     srange =  ( "[" spvalue 1*( "," spvalue ) "]" )
//                ; Discrete values separated by ','.
//                ; Each occurrence of spvalue MUST be
//                ; greater than the previous occurrence.
//             / ( "[" spvalue "-" spvalue "]" )
//                ; Range between a lower and an upper level (inclusive)
//                ; The second occurrence of spvalue MUST have a higher
//                ; value than the first
//             / ( spvalue )
//                ; A single value
//
//     prange =  ( "[" spvalue "-" spvalue "]" )
//                ; Range between a lower and an upper level (inclusive)
//                ; The second occurrence of spvalue MUST have a higher
//                ; value than the first
//
//     qvalue  = ( "0" "." 1*2DIGIT )
//             / ( "1" "." 1*2("0") )
//                ; Values between 0.00 and 1.00
//
//  XXX TBD -- We don't use this yet, and it's a project unto itself.
//

class SdpImageattrAttributeList : public SdpAttribute {
 public:
  SdpImageattrAttributeList() : SdpAttribute(kImageattrAttribute) {}

  class XYRange {
   public:
    XYRange() : min(0), max(0), step(1) {}
    void Serialize(std::ostream& os) const;
    // TODO: Remove this Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseAfterBracket(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseAfterMin(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseDiscreteValues(std::istream& is, std::string* error);
    std::vector<uint32_t> discreteValues;
    // min/max are used iff discreteValues is empty
    uint32_t min;
    uint32_t max;
    uint32_t step;
  };

  class SRange {
   public:
    SRange() : min(0), max(0) {}
    void Serialize(std::ostream& os) const;
    // TODO: Remove this Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseAfterBracket(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseAfterMin(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseDiscreteValues(std::istream& is, std::string* error);
    bool IsSet() const { return !discreteValues.empty() || (min && max); }
    std::vector<float> discreteValues;
    // min/max are used iff discreteValues is empty
    float min;
    float max;
  };

  class PRange {
   public:
    PRange() : min(0), max(0) {}
    void Serialize(std::ostream& os) const;
    // TODO: Remove this Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    bool IsSet() const { return min && max; }
    float min;
    float max;
  };

  class Set {
   public:
    Set() : qValue(-1) {}
    void Serialize(std::ostream& os) const;
    // TODO: Remove this Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    XYRange xRange;
    XYRange yRange;
    SRange sRange;
    PRange pRange;
    float qValue;
  };

  class Imageattr {
   public:
    Imageattr() : sendAll(false), recvAll(false) {}
    void Serialize(std::ostream& os) const;
    // TODO: Remove this Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    // TODO: Remove this Bug 1469702
    bool ParseSets(std::istream& is, std::string* error);
    // If not set, this means all payload types
    Maybe<uint16_t> pt;
    bool sendAll;
    std::vector<Set> sendSets;
    bool recvAll;
    std::vector<Set> recvSets;
  };

  SdpAttribute* Clone() const override {
    return new SdpImageattrAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  // TODO: Remove this Bug 1469702
  bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);

  std::vector<Imageattr> mImageattrs;
};

///////////////////////////////////////////////////////////////////////////
// a=msid, draft-ietf-mmusic-msid
//-------------------------------------------------------------------------
//   msid-attr = "msid:" identifier [ SP appdata ]
//   identifier = 1*64token-char ; see RFC 4566
//   appdata = 1*64token-char  ; see RFC 4566
class SdpMsidAttributeList : public SdpAttribute {
 public:
  SdpMsidAttributeList() : SdpAttribute(kMsidAttribute) {}

  struct Msid {
    std::string identifier;
    std::string appdata;
  };

  void PushEntry(const std::string& identifier,
                 const std::string& appdata = "") {
    Msid value = {identifier, appdata};
    mMsids.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpMsidAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Msid> mMsids;
};

///////////////////////////////////////////////////////////////////////////
// a=msid-semantic, draft-ietf-mmusic-msid
//-------------------------------------------------------------------------
//   msid-semantic-attr = "msid-semantic:" msid-semantic msid-list
//   msid-semantic = token ; see RFC 4566
//   msid-list = *(" " msid-id) / " *"
class SdpMsidSemanticAttributeList : public SdpAttribute {
 public:
  SdpMsidSemanticAttributeList() : SdpAttribute(kMsidSemanticAttribute) {}

  struct MsidSemantic {
    // TODO: Once we have some more of these, we might want to make an enum
    std::string semantic;
    std::vector<std::string> msids;
  };

  void PushEntry(const std::string& semantic,
                 const std::vector<std::string>& msids) {
    MsidSemantic value = {semantic, msids};
    mMsidSemantics.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpMsidSemanticAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<MsidSemantic> mMsidSemantics;
};

///////////////////////////////////////////////////////////////////////////
// a=remote-candiate, RFC5245
//-------------------------------------------------------------------------
//   remote-candidate-att = "remote-candidates" ":" remote-candidate
//                           0*(SP remote-candidate)
//   remote-candidate = component-ID SP connection-address SP port
class SdpRemoteCandidatesAttribute : public SdpAttribute {
 public:
  struct Candidate {
    std::string id;
    std::string address;
    uint16_t port;
  };

  explicit SdpRemoteCandidatesAttribute(
      const std::vector<Candidate>& candidates)
      : SdpAttribute(kRemoteCandidatesAttribute), mCandidates(candidates) {}

  SdpAttribute* Clone() const override {
    return new SdpRemoteCandidatesAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Candidate> mCandidates;
};

/*
a=rid, draft-pthatcher-mmusic-rid-01

   rid-syntax        = "a=rid:" rid-identifier SP rid-dir
                       [ rid-pt-param-list / rid-param-list ]

   rid-identifier    = 1*(alpha-numeric / "-" / "_")

   rid-dir           = "send" / "recv"

   rid-pt-param-list = SP rid-fmt-list *(";" rid-param)

   rid-param-list    = SP rid-param *(";" rid-param)

   rid-fmt-list      = "pt=" fmt *( "," fmt )
                        ; fmt defined in {{RFC4566}}

   rid-param         = rid-width-param
                       / rid-height-param
                       / rid-fps-param
                       / rid-fs-param
                       / rid-br-param
                       / rid-pps-param
                       / rid-depend-param
                       / rid-param-other

   rid-width-param   = "max-width" [ "=" int-param-val ]

   rid-height-param  = "max-height" [ "=" int-param-val ]

   rid-fps-param     = "max-fps" [ "=" int-param-val ]

   rid-fs-param      = "max-fs" [ "=" int-param-val ]

   rid-br-param      = "max-br" [ "=" int-param-val ]

   rid-pps-param     = "max-pps" [ "=" int-param-val ]

   rid-depend-param  = "depend=" rid-list

   rid-param-other   = 1*(alpha-numeric / "-") [ "=" param-val ]

   rid-list          = rid-identifier *( "," rid-identifier )

   int-param-val     = 1*DIGIT

   param-val         = *( %x20-58 / %x60-7E )
                       ; Any printable character except semicolon
*/

class SdpRidAttributeList : public SdpAttribute {
 public:
  explicit SdpRidAttributeList() : SdpAttribute(kRidAttribute) {}

  struct Rid {
    Rid() : direction(sdp::kSend) {}

    // Remove this function. See Bug 1469702
    bool Parse(std::istream& is, std::string* error);
    // Remove this function. See Bug 1469702
    bool ParseParameters(std::istream& is, std::string* error);
    // Remove this function. See Bug 1469702
    bool ParseDepend(std::istream& is, std::string* error);
    // Remove this function. See Bug 1469702
    bool ParseFormats(std::istream& is, std::string* error);

    void Serialize(std::ostream& os) const;
    void SerializeParameters(std::ostream& os) const;
    bool HasFormat(const std::string& format) const;
    bool HasParameters() const {
      return !formats.empty() || constraints.maxWidth ||
             constraints.maxHeight || constraints.maxFps || constraints.maxFs ||
             constraints.maxBr || constraints.maxPps || !dependIds.empty();
    }

    std::string id;
    sdp::Direction direction;
    std::vector<uint16_t> formats;  // Empty implies all
    EncodingConstraints constraints;
    std::vector<std::string> dependIds;
  };

  SdpAttribute* Clone() const override {
    return new SdpRidAttributeList(*this);
  }

  static bool CheckRidValidity(const std::string& aRid, std::string* aError);
  static size_t kMaxRidLength;

  virtual void Serialize(std::ostream& os) const override;

  // Remove this function. See Bug 1469702
  bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);

  void PushEntry(const std::string& id, sdp::Direction dir,
                 const std::vector<uint16_t>& formats,
                 const EncodingConstraints& constraints,
                 const std::vector<std::string>& dependIds);

  std::vector<Rid> mRids;
};

///////////////////////////////////////////////////////////////////////////
// a=rtcp, RFC3605
//-------------------------------------------------------------------------
//   rtcp-attribute =  "a=rtcp:" port  [nettype space addrtype space
//                         connection-address] CRLF
class SdpRtcpAttribute : public SdpAttribute {
 public:
  explicit SdpRtcpAttribute(uint16_t port)
      : SdpAttribute(kRtcpAttribute),
        mPort(port),
        mNetType(sdp::kNetTypeNone),
        mAddrType(sdp::kAddrTypeNone) {}

  SdpRtcpAttribute(uint16_t port, sdp::NetType netType, sdp::AddrType addrType,
                   const std::string& address)
      : SdpAttribute(kRtcpAttribute),
        mPort(port),
        mNetType(netType),
        mAddrType(addrType),
        mAddress(address) {
    MOZ_ASSERT(netType != sdp::kNetTypeNone);
    MOZ_ASSERT(addrType != sdp::kAddrTypeNone);
    MOZ_ASSERT(!address.empty());
  }

  SdpAttribute* Clone() const override { return new SdpRtcpAttribute(*this); }

  virtual void Serialize(std::ostream& os) const override;

  uint16_t mPort;
  sdp::NetType mNetType;
  sdp::AddrType mAddrType;
  std::string mAddress;
};

///////////////////////////////////////////////////////////////////////////
// a=rtcp-fb, RFC4585
//-------------------------------------------------------------------------
//    rtcp-fb-syntax = "a=rtcp-fb:" rtcp-fb-pt SP rtcp-fb-val CRLF
//
//    rtcp-fb-pt         = "*"   ; wildcard: applies to all formats
//                       / fmt   ; as defined in SDP spec
//
//    rtcp-fb-val        = "ack" rtcp-fb-ack-param
//                       / "nack" rtcp-fb-nack-param
//                       / "trr-int" SP 1*DIGIT
//                       / rtcp-fb-id rtcp-fb-param
//
//    rtcp-fb-id         = 1*(alpha-numeric / "-" / "_")
//
//    rtcp-fb-param      = SP "app" [SP byte-string]
//                       / SP token [SP byte-string]
//                       / ; empty
//
//    rtcp-fb-ack-param  = SP "rpsi"
//                       / SP "app" [SP byte-string]
//                       / SP token [SP byte-string]
//                       / ; empty
//
//    rtcp-fb-nack-param = SP "pli"
//                       / SP "sli"
//                       / SP "rpsi"
//                       / SP "app" [SP byte-string]
//                       / SP token [SP byte-string]
//                       / ; empty
//
class SdpRtcpFbAttributeList : public SdpAttribute {
 public:
  SdpRtcpFbAttributeList() : SdpAttribute(kRtcpFbAttribute) {}

  enum Type { kAck, kApp, kCcm, kNack, kTrrInt, kRemb, kTransportCC };

  static const char* pli;
  static const char* sli;
  static const char* rpsi;
  static const char* app;

  static const char* fir;
  static const char* tmmbr;
  static const char* tstr;
  static const char* vbcm;

  struct Feedback {
    std::string pt;
    Type type;
    std::string parameter;
    std::string extra;
    // TODO(bug 1744307): Use =default here once it is supported
    bool operator==(const Feedback& aOther) const {
      return pt == aOther.pt && type == aOther.type &&
             parameter == aOther.parameter && extra == aOther.extra;
    }
  };

  void PushEntry(const std::string& pt, Type type,
                 const std::string& parameter = "",
                 const std::string& extra = "") {
    Feedback value = {pt, type, parameter, extra};
    mFeedbacks.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpRtcpFbAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Feedback> mFeedbacks;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpRtcpFbAttributeList::Type type) {
  switch (type) {
    case SdpRtcpFbAttributeList::kAck:
      os << "ack";
      break;
    case SdpRtcpFbAttributeList::kApp:
      os << "app";
      break;
    case SdpRtcpFbAttributeList::kCcm:
      os << "ccm";
      break;
    case SdpRtcpFbAttributeList::kNack:
      os << "nack";
      break;
    case SdpRtcpFbAttributeList::kTrrInt:
      os << "trr-int";
      break;
    case SdpRtcpFbAttributeList::kRemb:
      os << "goog-remb";
      break;
    case SdpRtcpFbAttributeList::kTransportCC:
      os << "transport-cc";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=rtpmap, RFC4566
//-------------------------------------------------------------------------
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
class SdpRtpmapAttributeList : public SdpAttribute {
 public:
  SdpRtpmapAttributeList() : SdpAttribute(kRtpmapAttribute) {}

  // Minimal set to get going
  enum CodecType {
    kOpus,
    kG722,
    kPCMU,
    kPCMA,
    kVP8,
    kVP9,
    kiLBC,
    kiSAC,
    kH264,
    kAV1,
    kRed,
    kUlpfec,
    kTelephoneEvent,
    kRtx,
    kOtherCodec
  };

  struct Rtpmap {
    std::string pt;
    CodecType codec;
    std::string name;
    uint32_t clock;
    // Technically, this could mean something else in the future.
    // In practice, that's probably not going to happen.
    uint32_t channels;
  };

  void PushEntry(const std::string& pt, CodecType codec,
                 const std::string& name, uint32_t clock,
                 uint32_t channels = 0) {
    Rtpmap value = {pt, codec, name, clock, channels};
    mRtpmaps.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpRtpmapAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  bool HasEntry(const std::string& pt) const {
    for (auto it = mRtpmaps.begin(); it != mRtpmaps.end(); ++it) {
      if (it->pt == pt) {
        return true;
      }
    }
    return false;
  }

  const Rtpmap& GetEntry(const std::string& pt) const {
    for (auto it = mRtpmaps.begin(); it != mRtpmaps.end(); ++it) {
      if (it->pt == pt) {
        return *it;
      }
    }
    MOZ_CRASH();
  }

  std::vector<Rtpmap> mRtpmaps;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpRtpmapAttributeList::CodecType c) {
  switch (c) {
    case SdpRtpmapAttributeList::kOpus:
      os << "opus";
      break;
    case SdpRtpmapAttributeList::kG722:
      os << "G722";
      break;
    case SdpRtpmapAttributeList::kPCMU:
      os << "PCMU";
      break;
    case SdpRtpmapAttributeList::kPCMA:
      os << "PCMA";
      break;
    case SdpRtpmapAttributeList::kVP8:
      os << "VP8";
      break;
    case SdpRtpmapAttributeList::kVP9:
      os << "VP9";
      break;
    case SdpRtpmapAttributeList::kiLBC:
      os << "iLBC";
      break;
    case SdpRtpmapAttributeList::kiSAC:
      os << "iSAC";
      break;
    case SdpRtpmapAttributeList::kH264:
      os << "H264";
      break;
    case SdpRtpmapAttributeList::kAV1:
      os << "AV1";
      break;
    case SdpRtpmapAttributeList::kRed:
      os << "red";
      break;
    case SdpRtpmapAttributeList::kUlpfec:
      os << "ulpfec";
      break;
    case SdpRtpmapAttributeList::kTelephoneEvent:
      os << "telephone-event";
      break;
    case SdpRtpmapAttributeList::kRtx:
      os << "rtx";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
// a=fmtp, RFC4566, RFC5576
//-------------------------------------------------------------------------
//       a=fmtp:<format> <format specific parameters>
//
class SdpFmtpAttributeList : public SdpAttribute {
 public:
  SdpFmtpAttributeList() : SdpAttribute(kFmtpAttribute) {}

  // Base class for format parameters
  class Parameters {
   public:
    explicit Parameters(SdpRtpmapAttributeList::CodecType aCodec)
        : codec_type(aCodec) {}

    virtual ~Parameters() = default;
    virtual Parameters* Clone() const = 0;
    virtual bool ShouldSerialize() const { return true; }
    virtual void Serialize(std::ostream& os) const = 0;
    virtual bool CompareEq(const Parameters& other) const = 0;

    bool operator==(const Parameters& other) const {
      return codec_type == other.codec_type && CompareEq(other);
    }
    SdpRtpmapAttributeList::CodecType codec_type;
  };

  class RedParameters : public Parameters {
   public:
    RedParameters() : Parameters(SdpRtpmapAttributeList::kRed) {}

    virtual Parameters* Clone() const override {
      return new RedParameters(*this);
    }

    virtual void Serialize(std::ostream& os) const override {
      for (size_t i = 0; i < encodings.size(); ++i) {
        os << (i != 0 ? "/" : "") << std::to_string(encodings[i]);
      }
    }

    virtual bool CompareEq(const Parameters& other) const override {
      return encodings == static_cast<const RedParameters&>(other).encodings;
    }

    std::vector<uint8_t> encodings;
  };

  struct Av1Parameters : public Parameters {
    // https://aomediacodec.github.io/av1-rtp-spec/#722-rid-restrictions-mapping-for-av1
    Maybe<uint8_t> profile;
    static constexpr uint8_t kDefaultProfile = 0;
    Maybe<uint8_t> levelIdx;
    static constexpr uint8_t kDefaultLevelIdx = 5;
    Maybe<uint8_t> tier;
    static constexpr uint8_t kDefaultTier = 0;

    Av1Parameters() : Parameters(SdpRtpmapAttributeList::kAV1) {}
    Av1Parameters(const Av1Parameters&) = default;

    virtual ~Av1Parameters() = default;

    virtual Parameters* Clone() const override {
      return new Av1Parameters(*this);
    }

    // Returns the profile parameter if set, or the spec mandated default of 0.
    auto profileValue() const -> uint8_t {
      return profile.valueOr(kDefaultProfile);
    }
    // Returns the level-idx parameter if set, or the spec mandated default of
    // 5.
    auto levelIdxValue() const -> uint8_t {
      return levelIdx.valueOr(kDefaultLevelIdx);
    }
    // Returns the tier parameter if set, or the spec mandated default of 0.
    auto tierValue() const -> uint8_t { return tier.valueOr(kDefaultTier); }

    virtual bool ShouldSerialize() const override {
      return profile.isSome() || levelIdx.isSome() || tier.isSome();
    };

    virtual void Serialize(std::ostream& os) const override {
      bool first = true;
      profile.apply([&](const auto& profileV) {
        os << "profile=" << static_cast<int>(profileV);
        first = false;
      });
      levelIdx.apply([&](const auto& levelIdxV) {
        os << (first ? "" : ";") << "level-idx=" << static_cast<int>(levelIdxV);
        first = false;
      });
      tier.apply([&](const auto& tierV) {
        os << (first ? "" : ";") << "tier=" << static_cast<int>(tierV);
      });
    }

    virtual bool CompareEq(const Parameters& aOther) const override {
      return aOther.codec_type == codec_type &&
             static_cast<const Av1Parameters&>(aOther).profile == profile &&
             static_cast<const Av1Parameters&>(aOther).levelIdx == levelIdx &&
             static_cast<const Av1Parameters&>(aOther).tier == tier;
    }
  };

  class RtxParameters : public Parameters {
   public:
    uint8_t apt = 255;  // Valid payload types are 0 - 127, use 255 to represent
                        // unset value.
    Maybe<uint32_t> rtx_time;

    RtxParameters() : Parameters(SdpRtpmapAttributeList::kRtx) {}

    virtual ~RtxParameters() = default;

    virtual Parameters* Clone() const override {
      return new RtxParameters(*this);
    }

    virtual void Serialize(std::ostream& os) const override {
      if (apt <= 127) {
        os << "apt=" << static_cast<uint32_t>(apt);
        rtx_time.apply([&](const auto& time) { os << ";rtx-time=" << time; });
      }
    }

    virtual bool CompareEq(const Parameters& aOther) const override {
      if (aOther.codec_type != codec_type) {
        return false;
      }
      auto other = static_cast<const RtxParameters&>(aOther);
      return other.apt == apt && other.rtx_time == rtx_time;
    }
  };

  class H264Parameters : public Parameters {
   public:
    // Baseline no constraints level 1
    static const uint32_t kDefaultProfileLevelId = 0x42000A;

    H264Parameters()
        : Parameters(SdpRtpmapAttributeList::kH264),
          packetization_mode(0),
          level_asymmetry_allowed(false),
          profile_level_id(kDefaultProfileLevelId),
          max_mbps(0),
          max_fs(0),
          max_cpb(0),
          max_dpb(0),
          max_br(0) {
      memset(sprop_parameter_sets, 0, sizeof(sprop_parameter_sets));
    }

    virtual Parameters* Clone() const override {
      return new H264Parameters(*this);
    }

    virtual void Serialize(std::ostream& os) const override {
      // Note: don't move this, since having an unconditional param up top
      // lets us avoid a whole bunch of conditional streaming of ';' below
      os << "profile-level-id=" << std::hex << std::setfill('0') << std::setw(6)
         << profile_level_id << std::dec << std::setfill(' ');

      os << ";level-asymmetry-allowed=" << (level_asymmetry_allowed ? 1 : 0);

      if (strlen(sprop_parameter_sets)) {
        os << ";sprop-parameter-sets=" << sprop_parameter_sets;
      }

      if (packetization_mode != 0) {
        os << ";packetization-mode=" << packetization_mode;
      }

      if (max_mbps != 0) {
        os << ";max-mbps=" << max_mbps;
      }

      if (max_fs != 0) {
        os << ";max-fs=" << max_fs;
      }

      if (max_cpb != 0) {
        os << ";max-cpb=" << max_cpb;
      }

      if (max_dpb != 0) {
        os << ";max-dpb=" << max_dpb;
      }

      if (max_br != 0) {
        os << ";max-br=" << max_br;
      }
    }

    virtual bool CompareEq(const Parameters& other) const override {
      const auto& otherH264 = static_cast<const H264Parameters&>(other);

      // sprop is not comapred here as it does not get parsed in the rsdparsa
      return packetization_mode == otherH264.packetization_mode &&
             level_asymmetry_allowed == otherH264.level_asymmetry_allowed &&
             profile_level_id == otherH264.profile_level_id &&
             max_mbps == otherH264.max_mbps && max_fs == otherH264.max_fs &&
             max_cpb == otherH264.max_cpb && max_dpb == otherH264.max_dpb &&
             max_br == otherH264.max_br;
    }

    static const size_t max_sprop_len = 128;
    char sprop_parameter_sets[max_sprop_len];
    unsigned int packetization_mode;
    bool level_asymmetry_allowed;
    unsigned int profile_level_id;
    unsigned int max_mbps;
    unsigned int max_fs;
    unsigned int max_cpb;
    unsigned int max_dpb;
    unsigned int max_br;
  };

  // Also used for VP9 since they share parameters
  class VP8Parameters : public Parameters {
   public:
    explicit VP8Parameters(SdpRtpmapAttributeList::CodecType type)
        : Parameters(type), max_fs(0), max_fr(0) {}

    virtual Parameters* Clone() const override {
      return new VP8Parameters(*this);
    }

    virtual void Serialize(std::ostream& os) const override {
      // draft-ietf-payload-vp8-11 says these are mandatory, upper layer
      // needs to ensure they're set properly.
      os << "max-fs=" << max_fs;
      os << ";max-fr=" << max_fr;
    }

    virtual bool CompareEq(const Parameters& other) const override {
      const auto& otherVP8 = static_cast<const VP8Parameters&>(other);

      return max_fs == otherVP8.max_fs && max_fr == otherVP8.max_fr;
    }

    unsigned int max_fs;
    unsigned int max_fr;
  };

  class OpusParameters : public Parameters {
   public:
    enum {
      kDefaultMaxPlaybackRate = 48000,
      kDefaultStereo = 0,
      kDefaultUseInBandFec = 0,
      kDefaultMaxAverageBitrate = 0,
      kDefaultUseDTX = 0,
      kDefaultFrameSize = 0,
      kDefaultMinFrameSize = 0,
      kDefaultMaxFrameSize = 0,
      kDefaultUseCbr = 0
    };
    OpusParameters()
        : Parameters(SdpRtpmapAttributeList::kOpus),
          maxplaybackrate(kDefaultMaxPlaybackRate),
          stereo(kDefaultStereo),
          useInBandFec(kDefaultUseInBandFec),
          maxAverageBitrate(kDefaultMaxAverageBitrate),
          useDTX(kDefaultUseDTX),
          frameSizeMs(kDefaultFrameSize),
          minFrameSizeMs(kDefaultMinFrameSize),
          maxFrameSizeMs(kDefaultMaxFrameSize),
          useCbr(kDefaultUseCbr) {}

    Parameters* Clone() const override { return new OpusParameters(*this); }

    void Serialize(std::ostream& os) const override {
      os << "maxplaybackrate=" << maxplaybackrate << ";stereo=" << stereo
         << ";useinbandfec=" << useInBandFec;

      if (useDTX) {
        os << ";usedtx=1";
      }
      if (maxAverageBitrate) {
        os << ";maxaveragebitrate=" << maxAverageBitrate;
      }
      if (frameSizeMs) {
        os << ";ptime=" << frameSizeMs;
      }
      if (minFrameSizeMs) {
        os << ";minptime=" << minFrameSizeMs;
      }
      if (maxFrameSizeMs) {
        os << ";maxptime=" << maxFrameSizeMs;
      }
      if (useCbr) {
        os << ";cbr=1";
      }
    }

    virtual bool CompareEq(const Parameters& other) const override {
      const auto& otherOpus = static_cast<const OpusParameters&>(other);

      bool maxplaybackrateIsEq = (maxplaybackrate == otherOpus.maxplaybackrate);

      // This is due to a bug in sipcc that causes maxplaybackrate to
      // always be 0 if it appears in the fmtp
      if (((maxplaybackrate == 0) && (otherOpus.maxplaybackrate != 0)) ||
          ((maxplaybackrate != 0) && (otherOpus.maxplaybackrate == 0))) {
        maxplaybackrateIsEq = true;
      }

      return maxplaybackrateIsEq && stereo == otherOpus.stereo &&
             useInBandFec == otherOpus.useInBandFec &&
             maxAverageBitrate == otherOpus.maxAverageBitrate &&
             useDTX == otherOpus.useDTX &&
             frameSizeMs == otherOpus.frameSizeMs &&
             minFrameSizeMs == otherOpus.minFrameSizeMs &&
             maxFrameSizeMs == otherOpus.maxFrameSizeMs &&
             useCbr == otherOpus.useCbr;
    }

    unsigned int maxplaybackrate;
    unsigned int stereo;
    unsigned int useInBandFec;
    uint32_t maxAverageBitrate;
    bool useDTX;
    uint32_t frameSizeMs;
    uint32_t minFrameSizeMs;
    uint32_t maxFrameSizeMs;
    bool useCbr;
  };

  class TelephoneEventParameters : public Parameters {
   public:
    TelephoneEventParameters()
        : Parameters(SdpRtpmapAttributeList::kTelephoneEvent),
          dtmfTones("0-15") {}

    virtual Parameters* Clone() const override {
      return new TelephoneEventParameters(*this);
    }

    void Serialize(std::ostream& os) const override { os << dtmfTones; }

    virtual bool CompareEq(const Parameters& other) const override {
      return dtmfTones ==
             static_cast<const TelephoneEventParameters&>(other).dtmfTones;
    }

    std::string dtmfTones;
  };

  class Fmtp {
   public:
    Fmtp(const std::string& aFormat, const Parameters& aParameters)
        : format(aFormat), parameters(aParameters.Clone()) {}

    // TODO: Rip all of this out when we have move semantics in the stl.
    Fmtp(const Fmtp& orig) { *this = orig; }

    Fmtp& operator=(const Fmtp& rhs) {
      if (this != &rhs) {
        format = rhs.format;
        parameters.reset(rhs.parameters ? rhs.parameters->Clone() : nullptr);
      }
      return *this;
    }

    bool operator==(const Fmtp& other) const {
      return format == other.format && *parameters == *other.parameters;
    }

    // The contract around these is as follows:
    // * |parameters| is only set if we recognized the media type and had
    //   a subclass of Parameters to represent that type of parameters
    // * |parameters| is a best-effort representation; it might be missing
    //   stuff
    // * Parameters::codec_type tells you the concrete class, eg
    //   kH264 -> H264Parameters
    std::string format;
    UniquePtr<Parameters> parameters;
  };

  bool operator==(const SdpFmtpAttributeList& other) const;

  SdpAttribute* Clone() const override {
    return new SdpFmtpAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  void PushEntry(const std::string& format, const Parameters& parameters) {
    mFmtps.push_back(Fmtp(format, parameters));
  }

  std::vector<Fmtp> mFmtps;
};

///////////////////////////////////////////////////////////////////////////
// a=sctpmap, draft-ietf-mmusic-sctp-sdp-05
//-------------------------------------------------------------------------
//      sctpmap-attr        =  "a=sctpmap:" sctpmap-number media-subtypes
// [streams]
//      sctpmap-number      =  1*DIGIT
//      protocol            =  labelstring
//        labelstring         =  text
//        text                =  byte-string
//      streams      =  1*DIGIT
//
// We're going to pretend that there are spaces where they make sense.
class SdpSctpmapAttributeList : public SdpAttribute {
 public:
  SdpSctpmapAttributeList() : SdpAttribute(kSctpmapAttribute) {}

  struct Sctpmap {
    std::string pt;
    std::string name;
    uint32_t streams;
  };

  void PushEntry(const std::string& pt, const std::string& name,
                 uint32_t streams = 0) {
    Sctpmap value = {pt, name, streams};
    mSctpmaps.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpSctpmapAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  bool HasEntry(const std::string& pt) const {
    for (auto it = mSctpmaps.begin(); it != mSctpmaps.end(); ++it) {
      if (it->pt == pt) {
        return true;
      }
    }
    return false;
  }

  const Sctpmap& GetFirstEntry() const { return mSctpmaps[0]; }

  std::vector<Sctpmap> mSctpmaps;
};

///////////////////////////////////////////////////////////////////////////
// a=setup, RFC4145
//-------------------------------------------------------------------------
//       setup-attr           =  "a=setup:" role
//       role                 =  "active" / "passive" / "actpass" / "holdconn"
class SdpSetupAttribute : public SdpAttribute {
 public:
  enum Role { kActive, kPassive, kActpass, kHoldconn };

  explicit SdpSetupAttribute(Role role)
      : SdpAttribute(kSetupAttribute), mRole(role) {}

  SdpAttribute* Clone() const override { return new SdpSetupAttribute(*this); }

  virtual void Serialize(std::ostream& os) const override;

  Role mRole;
};

inline std::ostream& operator<<(std::ostream& os, SdpSetupAttribute::Role r) {
  switch (r) {
    case SdpSetupAttribute::kActive:
      os << "active";
      break;
    case SdpSetupAttribute::kPassive:
      os << "passive";
      break;
    case SdpSetupAttribute::kActpass:
      os << "actpass";
      break;
    case SdpSetupAttribute::kHoldconn:
      os << "holdconn";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

// Old draft-04
// sc-attr     = "a=simulcast:" 1*2( WSP sc-str-list ) [WSP sc-pause-list]
// sc-str-list = sc-dir WSP sc-id-type "=" sc-alt-list *( ";" sc-alt-list )
// sc-pause-list = "paused=" sc-alt-list
// sc-dir      = "send" / "recv"
// sc-id-type  = "pt" / "rid" / token
// sc-alt-list = sc-id *( "," sc-id )
// sc-id       = fmt / rid-identifier / token
// ; WSP defined in [RFC5234]
// ; fmt, token defined in [RFC4566]
// ; rid-identifier defined in [I-D.pthatcher-mmusic-rid]
//
// New draft 14, need to parse this for now, will eventually emit it
// sc-value     = ( sc-send [SP sc-recv] ) / ( sc-recv [SP sc-send] )
// sc-send      = %s"send" SP sc-str-list
// sc-recv      = %s"recv" SP sc-str-list
// sc-str-list  = sc-alt-list *( ";" sc-alt-list )
// sc-alt-list  = sc-id *( "," sc-id )
// sc-id-paused = "~"
// sc-id        = [sc-id-paused] rid-id
// ; SP defined in [RFC5234]
// ; rid-id defined in [I-D.ietf-mmusic-rid]

class SdpSimulcastAttribute : public SdpAttribute {
 public:
  SdpSimulcastAttribute() : SdpAttribute(kSimulcastAttribute) {}

  SdpAttribute* Clone() const override {
    return new SdpSimulcastAttribute(*this);
  }

  void Serialize(std::ostream& os) const override;
  bool Parse(std::istream& is, std::string* error);

  class Encoding {
   public:
    Encoding(const std::string& aRid, bool aPaused)
        : rid(aRid), paused(aPaused) {}
    std::string rid;
    bool paused = false;
  };

  class Version {
   public:
    void Serialize(std::ostream& os) const;
    bool IsSet() const { return !choices.empty(); }
    bool Parse(std::istream& is, std::string* error);

    std::vector<Encoding> choices;
  };

  class Versions : public std::vector<Version> {
   public:
    void Serialize(std::ostream& os) const;
    bool IsSet() const {
      if (empty()) {
        return false;
      }

      for (const Version& version : *this) {
        if (version.IsSet()) {
          return true;
        }
      }

      return false;
    }

    bool Parse(std::istream& is, std::string* error);
  };

  Versions sendVersions;
  Versions recvVersions;
};

///////////////////////////////////////////////////////////////////////////
// a=ssrc, RFC5576
//-------------------------------------------------------------------------
// ssrc-attr = "ssrc:" ssrc-id SP attribute
// ; The base definition of "attribute" is in RFC 4566.
// ; (It is the content of "a=" lines.)
//
// ssrc-id = integer ; 0 .. 2**32 - 1
//-------------------------------------------------------------------------
// TODO -- In the future, it might be nice if we ran a parse on the
// attribute section of this so that we could interpret it semantically.
// For WebRTC, the key use case for a=ssrc is assocaiting SSRCs with
// media sections, and we're not really going to care about the attribute
// itself. So we're just going to store it as a string for the time being.
// Issue 187.
class SdpSsrcAttributeList : public SdpAttribute {
 public:
  SdpSsrcAttributeList() : SdpAttribute(kSsrcAttribute) {}

  struct Ssrc {
    uint32_t ssrc;
    std::string attribute;
  };

  void PushEntry(uint32_t ssrc, const std::string& attribute) {
    Ssrc value = {ssrc, attribute};
    mSsrcs.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpSsrcAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<Ssrc> mSsrcs;
};

///////////////////////////////////////////////////////////////////////////
// a=ssrc-group, RFC5576
//-------------------------------------------------------------------------
// ssrc-group-attr = "ssrc-group:" semantics *(SP ssrc-id)
//
// semantics       = "FEC" / "FID" / token
//
// ssrc-id = integer ; 0 .. 2**32 - 1
class SdpSsrcGroupAttributeList : public SdpAttribute {
 public:
  enum Semantics {
    kFec,    // RFC5576
    kFid,    // RFC5576
    kFecFr,  // RFC5956
    kDup,    // RFC7104
    kSim     // non-standard, used by hangouts
  };

  struct SsrcGroup {
    Semantics semantics;
    std::vector<uint32_t> ssrcs;
  };

  SdpSsrcGroupAttributeList() : SdpAttribute(kSsrcGroupAttribute) {}

  void PushEntry(Semantics semantics, const std::vector<uint32_t>& ssrcs) {
    SsrcGroup value = {semantics, ssrcs};
    mSsrcGroups.push_back(value);
  }

  SdpAttribute* Clone() const override {
    return new SdpSsrcGroupAttributeList(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<SsrcGroup> mSsrcGroups;
};

inline std::ostream& operator<<(std::ostream& os,
                                SdpSsrcGroupAttributeList::Semantics s) {
  switch (s) {
    case SdpSsrcGroupAttributeList::kFec:
      os << "FEC";
      break;
    case SdpSsrcGroupAttributeList::kFid:
      os << "FID";
      break;
    case SdpSsrcGroupAttributeList::kFecFr:
      os << "FEC-FR";
      break;
    case SdpSsrcGroupAttributeList::kDup:
      os << "DUP";
      break;
    case SdpSsrcGroupAttributeList::kSim:
      os << "SIM";
      break;
    default:
      MOZ_ASSERT(false);
      os << "?";
  }
  return os;
}

///////////////////////////////////////////////////////////////////////////
class SdpMultiStringAttribute : public SdpAttribute {
 public:
  explicit SdpMultiStringAttribute(AttributeType type) : SdpAttribute(type) {}

  void PushEntry(const std::string& entry) { mValues.push_back(entry); }

  SdpAttribute* Clone() const override {
    return new SdpMultiStringAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<std::string> mValues;
};

// otherwise identical to SdpMultiStringAttribute, this is used for
// ice-options and other places where the value is serialized onto
// a single line with space separating tokens
class SdpOptionsAttribute : public SdpAttribute {
 public:
  explicit SdpOptionsAttribute(AttributeType type) : SdpAttribute(type) {}

  void PushEntry(const std::string& entry) { mValues.push_back(entry); }

  void Load(const std::string& value);

  SdpAttribute* Clone() const override {
    return new SdpOptionsAttribute(*this);
  }

  virtual void Serialize(std::ostream& os) const override;

  std::vector<std::string> mValues;
};

// Used for attributes that take no value (eg; a=ice-lite)
class SdpFlagAttribute : public SdpAttribute {
 public:
  explicit SdpFlagAttribute(AttributeType type) : SdpAttribute(type) {}

  SdpAttribute* Clone() const override { return new SdpFlagAttribute(*this); }

  virtual void Serialize(std::ostream& os) const override;
};

// Used for any other kind of single-valued attribute not otherwise specialized
class SdpStringAttribute : public SdpAttribute {
 public:
  explicit SdpStringAttribute(AttributeType type, const std::string& value)
      : SdpAttribute(type), mValue(value) {}

  SdpAttribute* Clone() const override { return new SdpStringAttribute(*this); }

  virtual void Serialize(std::ostream& os) const override;

  std::string mValue;
};

// Used for any purely (non-negative) numeric attribute
class SdpNumberAttribute : public SdpAttribute {
 public:
  explicit SdpNumberAttribute(AttributeType type, uint32_t value = 0)
      : SdpAttribute(type), mValue(value) {}

  SdpAttribute* Clone() const override { return new SdpNumberAttribute(*this); }

  virtual void Serialize(std::ostream& os) const override;

  uint32_t mValue;
};

}  // namespace mozilla

#endif

Messung V0.5
C=83 H=99 G=91

¤ Dauer der Verarbeitung: 0.49 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.