1955 lines
60 KiB
C++
1955 lines
60 KiB
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,
|
|
kExtmapAllowMixedAttribute,
|
|
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
|