diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /dom/media/webrtc/sdp/SdpAttribute.h | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | dom/media/webrtc/sdp/SdpAttribute.h | 1907 |
1 files changed, 1907 insertions, 0 deletions
diff --git a/dom/media/webrtc/sdp/SdpAttribute.h b/dom/media/webrtc/sdp/SdpAttribute.h new file mode 100644 index 0000000000..6af497ac18 --- /dev/null +++ b/dom/media/webrtc/sdp/SdpAttribute.h @@ -0,0 +1,1907 @@ +/* -*- 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 "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() {} + + 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 std::ostream& operator<<(std::ostream& os, + SdpFingerprintAttributeList::HashAlgorithm a) { + switch (a) { + case SdpFingerprintAttributeList::kSha1: + os << "sha-1"; + break; + case SdpFingerprintAttributeList::kSha224: + os << "sha-224"; + break; + case SdpFingerprintAttributeList::kSha256: + os << "sha-256"; + break; + case SdpFingerprintAttributeList::kSha384: + os << "sha-384"; + break; + case SdpFingerprintAttributeList::kSha512: + os << "sha-512"; + break; + case SdpFingerprintAttributeList::kMd5: + os << "md5"; + break; + case SdpFingerprintAttributeList::kMd2: + os << "md2"; + break; + default: + MOZ_ASSERT(false); + os << "?"; + } + return os; +} + +/////////////////////////////////////////////////////////////////////////// +// 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() : pt(), 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, + 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::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() {} + virtual Parameters* Clone() const = 0; + 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; + }; + + 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() {} + + 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: + static const uint32_t kDefaultProfileLevelId = 0x420010; + + 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 |