summaryrefslogtreecommitdiffstats
path: root/media/webrtc/signaling/src/sdp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /media/webrtc/signaling/src/sdp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'media/webrtc/signaling/src/sdp')
-rw-r--r--media/webrtc/signaling/src/sdp/Sdp.h195
-rw-r--r--media/webrtc/signaling/src/sdp/SdpAttribute.cpp1674
-rw-r--r--media/webrtc/signaling/src/sdp/SdpAttribute.h1788
-rw-r--r--media/webrtc/signaling/src/sdp/SdpAttributeList.h94
-rw-r--r--media/webrtc/signaling/src/sdp/SdpEnum.h70
-rw-r--r--media/webrtc/signaling/src/sdp/SdpErrorHolder.h50
-rw-r--r--media/webrtc/signaling/src/sdp/SdpHelper.cpp811
-rw-r--r--media/webrtc/signaling/src/sdp/SdpHelper.h131
-rw-r--r--media/webrtc/signaling/src/sdp/SdpMediaSection.cpp196
-rw-r--r--media/webrtc/signaling/src/sdp/SdpMediaSection.h361
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdp.cpp180
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdp.h88
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp1413
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h147
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp423
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h102
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpParser.cpp83
-rw-r--r--media/webrtc/signaling/src/sdp/SipccSdpParser.h35
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/ccsdp.h207
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/ccsdp_rtcp_fb.h63
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_darwin_types.h68
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_linux_types.h82
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_string.c272
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_string.h139
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_strings.h22
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_types.h126
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/cpr_win_types.h71
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp.h1794
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_access.c2083
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c5120
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c6372
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c403
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_base64.h42
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_config.c241
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_main.c1342
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h27
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_private.h364
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_services_unix.c41
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_services_win32.c40
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_token.c1812
-rw-r--r--media/webrtc/signaling/src/sdp/sipcc/sdp_utils.c781
41 files changed, 29353 insertions, 0 deletions
diff --git a/media/webrtc/signaling/src/sdp/Sdp.h b/media/webrtc/signaling/src/sdp/Sdp.h
new file mode 100644
index 000000000..8eeb89e2f
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/Sdp.h
@@ -0,0 +1,195 @@
+/* -*- 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/. */
+
+/*
+
+ ,-----. ,--. ,--.
+ ' .--./ ,--,--.,--.,--.,-' '-.`--' ,---. ,--,--,
+ | | ' ,-. || || |'-. .-',--.| .-. || `
+ ' '--'\\ '-' |' '' ' | | | |' '-' '| || |
+ `-----' `--`--' `----' `--' `--' `---' `--''--'
+
+ :+o+-
+ -dNNNNNd.
+ yNNNNNNNs
+ :mNNNNNm-
+ `/sso/``-://-
+ .:+sydNNNNNNms: `://`
+ `-/+shmNNNNNNNNNNNNNNNms- :mNNNm/
+ `-/oydmNNNNNNNNNNNNNNNNNNNNNNNNdo- +NNNNNN+
+ .shmNNNNNNNNNNNmdyo/:dNNNNNNNNNNNNNNNNdo. `sNNNNNm+
+ hNNNNNNNNmhs+:-` .dNNNNNNNNNNNNNNNNNNNNh+-` `hNNNNNm:
+ -yddyo/:. -dNNNNm::ymNNNNNNNNNNNNNNNmdy+/dNNNNNd.
+ :mNNNNd. `/ymNNNNNNNNNNNNNNNNNNNNNNh`
+ +NNNNNh` `+hNNNNNNNNNNNNNNNNNNNs
+ sNNNNNy` .yNNNNNm`-/oymNNNm+
+ `yNNNNNo oNNNNNm` `-.
+ .dNNNNm/ oNNNNNm`
+ oNNNNm: +NNNNNm`
+ `+yho. +NNNNNm`
+ +NNNNNNs.
+ `yNNNNNNmy-
+ -smNNNNNNh:
+ .smNNNNNNh/
+ `omNNNNNNd:
+ `+dNNNNNd
+ ````......```` /hmdy-
+ `.:/+osyhddmNNMMMMMMMMMMMMMMMMMMMMNNmddhyso+/:.`
+ `-+shmNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNmhs+-`
+ -smMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMds-
+ hMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh
+ yMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMs
+ .ohNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNh+.
+ ./oydmMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMmhyo:.
+ `.:/+osyyhddmmNNMMMMMMMMMMMMMMNNmmddhyyso+/:.`
+
+ ,--------.,--. ,--. ,--.
+ '--. .--'| ,---. `--' ,---. | | ,---.
+ | | | .-. |,--.( .-' | |( .-'
+ | | | | | || |.-' `) | |.-' `)
+ `--' `--' `--'`--'`----' `--'`----'
+ ,--.
+ ,---. ,------. ,------. ,--. | |
+ ' .-' | .-. \ | .--. ' ,--,--.,--.--.,-' '-. ,--,--.| |
+ `. `-. | | \ :| '--' |' ,-. || .--''-. .-'' ,-. || |
+ .-' || '--' /| | --' \ '-' || | | | \ '-' |`--'
+ `-----' `-------' `--' `--`--'`--' `--' `--`--'.--.
+ '__'
+*/
+
+#ifndef _SDP_H_
+#define _SDP_H_
+
+#include <ostream>
+#include <vector>
+#include <sstream>
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Maybe.h"
+#include "signaling/src/sdp/SdpMediaSection.h"
+#include "signaling/src/sdp/SdpAttributeList.h"
+#include "signaling/src/sdp/SdpEnum.h"
+
+namespace mozilla
+{
+
+class SdpOrigin;
+class SdpEncryptionKey;
+class SdpMediaSection;
+
+/**
+ * Base class for an SDP
+ */
+class Sdp
+{
+public:
+ Sdp(){};
+ virtual ~Sdp(){};
+
+ virtual const SdpOrigin& GetOrigin() const = 0;
+ // Note: connection information is always retrieved from media sections
+ virtual uint32_t GetBandwidth(const std::string& type) const = 0;
+
+ virtual const SdpAttributeList& GetAttributeList() const = 0;
+ virtual SdpAttributeList& GetAttributeList() = 0;
+
+ virtual size_t GetMediaSectionCount() const = 0;
+ virtual const SdpMediaSection& GetMediaSection(size_t level) const = 0;
+ virtual SdpMediaSection& GetMediaSection(size_t level) = 0;
+
+ virtual SdpMediaSection& AddMediaSection(SdpMediaSection::MediaType media,
+ SdpDirectionAttribute::Direction dir,
+ uint16_t port,
+ SdpMediaSection::Protocol proto,
+ sdp::AddrType addrType,
+ const std::string& addr) = 0;
+
+ virtual void Serialize(std::ostream&) const = 0;
+
+ std::string ToString() const;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Sdp& sdp)
+{
+ sdp.Serialize(os);
+ return os;
+}
+
+inline std::string
+Sdp::ToString() const
+{
+ std::stringstream s;
+ s << *this;
+ return s.str();
+}
+
+class SdpOrigin
+{
+public:
+ SdpOrigin(const std::string& username, uint64_t sessId, uint64_t sessVer,
+ sdp::AddrType addrType, const std::string& addr)
+ : mUsername(username),
+ mSessionId(sessId),
+ mSessionVersion(sessVer),
+ mAddrType(addrType),
+ mAddress(addr)
+ {
+ }
+
+ const std::string&
+ GetUsername() const
+ {
+ return mUsername;
+ }
+
+ uint64_t
+ GetSessionId() const
+ {
+ return mSessionId;
+ }
+
+ uint64_t
+ GetSessionVersion() const
+ {
+ return mSessionVersion;
+ }
+
+ sdp::AddrType
+ GetAddrType() const
+ {
+ return mAddrType;
+ }
+
+ const std::string&
+ GetAddress() const
+ {
+ return mAddress;
+ }
+
+ void
+ Serialize(std::ostream& os) const
+ {
+ sdp::NetType netType = sdp::kInternet;
+ os << "o=" << mUsername << " " << mSessionId << " " << mSessionVersion
+ << " " << netType << " " << mAddrType << " " << mAddress << "\r\n";
+ }
+
+private:
+ std::string mUsername;
+ uint64_t mSessionId;
+ uint64_t mSessionVersion;
+ sdp::AddrType mAddrType;
+ std::string mAddress;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const SdpOrigin& origin)
+{
+ origin.Serialize(os);
+ return os;
+}
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SdpAttribute.cpp b/media/webrtc/signaling/src/sdp/SdpAttribute.cpp
new file mode 100644
index 000000000..06fc94dbb
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpAttribute.cpp
@@ -0,0 +1,1674 @@
+/* -*- 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/. */
+
+#include "signaling/src/sdp/SdpAttribute.h"
+#include "signaling/src/sdp/SdpHelper.h"
+#include <iomanip>
+
+#ifdef CRLF
+#undef CRLF
+#endif
+#define CRLF "\r\n"
+
+namespace mozilla
+{
+
+static unsigned char
+PeekChar(std::istream& is, std::string* error)
+{
+ int next = is.peek();
+ if (next == EOF) {
+ *error = "Truncated";
+ return 0;
+ }
+
+ return next;
+}
+
+static std::string ParseToken(std::istream& is,
+ const std::string& delims,
+ std::string* error)
+{
+ std::string token;
+ while (is) {
+ unsigned char c = PeekChar(is, error);
+ if (!c || (delims.find(c) != std::string::npos)) {
+ break;
+ }
+ token.push_back(std::tolower(is.get()));
+ }
+ return token;
+}
+
+static bool
+SkipChar(std::istream& is, unsigned char c, std::string* error)
+{
+ if (PeekChar(is, error) != c) {
+ *error = "Expected \'";
+ error->push_back(c);
+ error->push_back('\'');
+ return false;
+ }
+
+ is.get();
+ return true;
+}
+
+
+void
+SdpConnectionAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mValue << CRLF;
+}
+
+void
+SdpDirectionAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mValue << CRLF;
+}
+
+void
+SdpDtlsMessageAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mRole << " " << mValue << CRLF;
+}
+
+bool
+SdpDtlsMessageAttribute::Parse(std::istream& is, std::string* error)
+{
+ std::string roleToken = ParseToken(is, " ", error);
+ if (roleToken == "server") {
+ mRole = kServer;
+ } else if (roleToken == "client") {
+ mRole = kClient;
+ } else {
+ *error = "Invalid dtls-message role; must be either client or server";
+ return false;
+ }
+
+ is >> std::ws;
+
+ std::string s(std::istreambuf_iterator<char>(is), {});
+ mValue = s;
+
+ return true;
+}
+
+void
+SdpExtmapAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mExtmaps.begin(); i != mExtmaps.end(); ++i) {
+ os << "a=" << mType << ":" << i->entry;
+ if (i->direction_specified) {
+ os << "/" << i->direction;
+ }
+ os << " " << i->extensionname;
+ if (i->extensionattributes.length()) {
+ os << " " << i->extensionattributes;
+ }
+ os << CRLF;
+ }
+}
+
+void
+SdpFingerprintAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mFingerprints.begin(); i != mFingerprints.end(); ++i) {
+ os << "a=" << mType << ":" << i->hashFunc << " "
+ << FormatFingerprint(i->fingerprint) << CRLF;
+ }
+}
+
+// Format the fingerprint in RFC 4572 Section 5 attribute format
+std::string
+SdpFingerprintAttributeList::FormatFingerprint(const std::vector<uint8_t>& fp)
+{
+ if (fp.empty()) {
+ MOZ_ASSERT(false, "Cannot format an empty fingerprint.");
+ return "";
+ }
+
+ std::ostringstream os;
+ for (auto i = fp.begin(); i != fp.end(); ++i) {
+ os << ":" << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
+ << static_cast<uint32_t>(*i);
+ }
+ return os.str().substr(1);
+}
+
+static uint8_t
+FromUppercaseHex(char ch)
+{
+ if ((ch >= '0') && (ch <= '9')) {
+ return ch - '0';
+ }
+ if ((ch >= 'A') && (ch <= 'F')) {
+ return ch - 'A' + 10;
+ }
+ return 16; // invalid
+}
+
+// Parse the fingerprint from RFC 4572 Section 5 attribute format
+std::vector<uint8_t>
+SdpFingerprintAttributeList::ParseFingerprint(const std::string& str)
+{
+ size_t targetSize = (str.length() + 1) / 3;
+ std::vector<uint8_t> fp(targetSize);
+ size_t fpIndex = 0;
+
+ if (str.length() % 3 != 2) {
+ fp.clear();
+ return fp;
+ }
+
+ for (size_t i = 0; i < str.length(); i += 3) {
+ uint8_t high = FromUppercaseHex(str[i]);
+ uint8_t low = FromUppercaseHex(str[i + 1]);
+ if (high > 0xf || low > 0xf ||
+ (i + 2 < str.length() && str[i + 2] != ':')) {
+ fp.clear(); // error
+ return fp;
+ }
+ fp[fpIndex++] = high << 4 | low;
+ }
+ return fp;
+}
+
+void
+SdpFmtpAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mFmtps.begin(); i != mFmtps.end(); ++i) {
+ if (i->parameters) {
+ os << "a=" << mType << ":" << i->format << " ";
+ i->parameters->Serialize(os);
+ os << CRLF;
+ }
+ }
+}
+
+void
+SdpGroupAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mGroups.begin(); i != mGroups.end(); ++i) {
+ os << "a=" << mType << ":" << i->semantics;
+ for (auto j = i->tags.begin(); j != i->tags.end(); ++j) {
+ os << " " << (*j);
+ }
+ os << CRLF;
+ }
+}
+
+// We're just using an SdpStringAttribute for this right now
+#if 0
+void SdpIdentityAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mAssertion;
+ for (auto i = mExtensions.begin(); i != mExtensions.end(); i++) {
+ os << (i == mExtensions.begin() ? " " : ";") << (*i);
+ }
+ os << CRLF;
+}
+#endif
+
+// Class to help with omitting a leading delimiter for the first item in a list
+class SkipFirstDelimiter
+{
+ public:
+ explicit SkipFirstDelimiter(const std::string& delim) :
+ mDelim(delim),
+ mFirst(true)
+ {}
+
+ std::ostream& print(std::ostream& os)
+ {
+ if (!mFirst) {
+ os << mDelim;
+ }
+ mFirst = false;
+ return os;
+ }
+
+ private:
+ std::string mDelim;
+ bool mFirst;
+};
+
+static std::ostream& operator<<(std::ostream& os, SkipFirstDelimiter& delim)
+{
+ return delim.print(os);
+}
+
+void
+SdpImageattrAttributeList::XYRange::Serialize(std::ostream& os) const
+{
+ if (discreteValues.size() == 0) {
+ os << "[" << min << ":";
+ if (step != 1) {
+ os << step << ":";
+ }
+ os << max << "]";
+ } else if (discreteValues.size() == 1) {
+ os << discreteValues.front();
+ } else {
+ os << "[";
+ SkipFirstDelimiter comma(",");
+ for (auto value : discreteValues) {
+ os << comma << value;
+ }
+ os << "]";
+ }
+}
+
+template<typename T>
+bool
+GetUnsigned(std::istream& is, T min, T max, T* value, std::string* error)
+{
+ if (PeekChar(is, error) == '-') {
+ *error = "Value is less than 0";
+ return false;
+ }
+
+ is >> std::noskipws >> *value;
+
+ if (is.fail()) {
+ *error = "Malformed";
+ return false;
+ }
+
+ if (*value < min) {
+ *error = "Value too small";
+ return false;
+ }
+
+ if (*value > max) {
+ *error = "Value too large";
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+GetXYValue(std::istream& is, uint32_t* value, std::string* error)
+{
+ return GetUnsigned<uint32_t>(is, 1, 999999, value, error);
+}
+
+bool
+SdpImageattrAttributeList::XYRange::ParseDiscreteValues(std::istream& is,
+ std::string* error)
+{
+ do {
+ uint32_t value;
+ if (!GetXYValue(is, &value, error)) {
+ return false;
+ }
+ discreteValues.push_back(value);
+ } while (SkipChar(is, ',', error));
+
+ return SkipChar(is, ']', error);
+}
+
+bool
+SdpImageattrAttributeList::XYRange::ParseAfterMin(std::istream& is,
+ std::string* error)
+{
+ // We have already parsed "[320:", and now expect another uint
+ uint32_t value;
+ if (!GetXYValue(is, &value, error)) {
+ return false;
+ }
+
+ if (SkipChar(is, ':', error)) {
+ // Range with step eg [320:16:640]
+ step = value;
+ // Now |value| should be the max
+ if (!GetXYValue(is, &value, error)) {
+ return false;
+ }
+ }
+
+ max = value;
+ if (min >= max) {
+ *error = "Min is not smaller than max";
+ return false;
+ }
+
+ return SkipChar(is, ']', error);
+}
+
+bool
+SdpImageattrAttributeList::XYRange::ParseAfterBracket(std::istream& is,
+ std::string* error)
+{
+ // Either a range, or a list of discrete values
+ // [320:640], [320:16:640], or [320,640]
+ uint32_t value;
+ if (!GetXYValue(is, &value, error)) {
+ return false;
+ }
+
+ if (SkipChar(is, ':', error)) {
+ // Range - [640:480] or [640:16:480]
+ min = value;
+ return ParseAfterMin(is, error);
+ }
+
+ if (SkipChar(is, ',', error)) {
+ discreteValues.push_back(value);
+ return ParseDiscreteValues(is, error);
+ }
+
+ *error = "Expected \':\' or \',\'";
+ return false;
+}
+
+bool
+SdpImageattrAttributeList::XYRange::Parse(std::istream& is, std::string* error)
+{
+ if (SkipChar(is, '[', error)) {
+ return ParseAfterBracket(is, error);
+ }
+
+ // Single discrete value
+ uint32_t value;
+ if (!GetXYValue(is, &value, error)) {
+ return false;
+ }
+ discreteValues.push_back(value);
+
+ return true;
+}
+
+static bool
+GetSPValue(std::istream& is, float* value, std::string* error)
+{
+ return GetUnsigned<float>(is, 0.1f, 9.9999f, value, error);
+}
+
+static bool
+GetQValue(std::istream& is, float* value, std::string* error)
+{
+ return GetUnsigned<float>(is, 0.0f, 1.0f, value, error);
+}
+
+bool
+SdpImageattrAttributeList::SRange::ParseDiscreteValues(std::istream& is,
+ std::string* error)
+{
+ do {
+ float value;
+ if (!GetSPValue(is, &value, error)) {
+ return false;
+ }
+ discreteValues.push_back(value);
+ } while (SkipChar(is, ',', error));
+
+ return SkipChar(is, ']', error);
+}
+
+bool
+SdpImageattrAttributeList::SRange::ParseAfterMin(std::istream& is,
+ std::string* error)
+{
+ if (!GetSPValue(is, &max, error)) {
+ return false;
+ }
+
+ if (min >= max) {
+ *error = "Min is not smaller than max";
+ return false;
+ }
+
+ return SkipChar(is, ']', error);
+}
+
+bool
+SdpImageattrAttributeList::SRange::ParseAfterBracket(std::istream& is,
+ std::string* error)
+{
+ // Either a range, or a list of discrete values
+ float value;
+ if (!GetSPValue(is, &value, error)) {
+ return false;
+ }
+
+ if (SkipChar(is, '-', error)) {
+ min = value;
+ return ParseAfterMin(is, error);
+ }
+
+ if (SkipChar(is, ',', error)) {
+ discreteValues.push_back(value);
+ return ParseDiscreteValues(is, error);
+ }
+
+ *error = "Expected either \'-\' or \',\'";
+ return false;
+}
+
+bool
+SdpImageattrAttributeList::SRange::Parse(std::istream& is, std::string* error)
+{
+ if (SkipChar(is, '[', error)) {
+ return ParseAfterBracket(is, error);
+ }
+
+ // Single discrete value
+ float value;
+ if (!GetSPValue(is, &value, error)) {
+ return false;
+ }
+ discreteValues.push_back(value);
+ return true;
+}
+
+bool
+SdpImageattrAttributeList::PRange::Parse(std::istream& is, std::string* error)
+{
+ if (!SkipChar(is, '[', error)) {
+ return false;
+ }
+
+ if (!GetSPValue(is, &min, error)) {
+ return false;
+ }
+
+ if (!SkipChar(is, '-', error)) {
+ return false;
+ }
+
+ if (!GetSPValue(is, &max, error)) {
+ return false;
+ }
+
+ if (min >= max) {
+ *error = "min must be smaller than max";
+ return false;
+ }
+
+ if (!SkipChar(is, ']', error)) {
+ return false;
+ }
+ return true;
+}
+
+void
+SdpImageattrAttributeList::SRange::Serialize(std::ostream& os) const
+{
+ os << std::setprecision(4) << std::fixed;
+ if (discreteValues.size() == 0) {
+ os << "[" << min << "-" << max << "]";
+ } else if (discreteValues.size() == 1) {
+ os << discreteValues.front();
+ } else {
+ os << "[";
+ SkipFirstDelimiter comma(",");
+ for (auto value : discreteValues) {
+ os << comma << value;
+ }
+ os << "]";
+ }
+}
+
+void
+SdpImageattrAttributeList::PRange::Serialize(std::ostream& os) const
+{
+ os << std::setprecision(4) << std::fixed;
+ os << "[" << min << "-" << max << "]";
+}
+
+static std::string ParseKey(std::istream& is, std::string* error)
+{
+ std::string token = ParseToken(is, "=", error);
+ if (!SkipChar(is, '=', error)) {
+ return "";
+ }
+ return token;
+}
+
+static bool SkipBraces(std::istream& is, std::string* error)
+{
+ if (PeekChar(is, error) != '[') {
+ *error = "Expected \'[\'";
+ return false;
+ }
+
+ size_t braceCount = 0;
+ do {
+ switch (PeekChar(is, error)) {
+ case '[':
+ ++braceCount;
+ break;
+ case ']':
+ --braceCount;
+ break;
+ default:
+ break;
+ }
+ is.get();
+ } while (braceCount && is);
+
+ if (!is) {
+ *error = "Expected closing brace";
+ return false;
+ }
+
+ return true;
+}
+
+// Assumptions:
+// 1. If the value contains '[' or ']', they are balanced.
+// 2. The value contains no ',' outside of brackets.
+static bool SkipValue(std::istream& is, std::string* error)
+{
+ while (is) {
+ switch (PeekChar(is, error)) {
+ case ',':
+ case ']':
+ return true;
+ case '[':
+ if (!SkipBraces(is, error)) {
+ return false;
+ }
+ break;
+ default:
+ is.get();
+ }
+ }
+
+ *error = "No closing \']\' on set";
+ return false;
+}
+
+bool
+SdpImageattrAttributeList::Set::Parse(std::istream& is, std::string* error)
+{
+ if (!SkipChar(is, '[', error)) {
+ return false;
+ }
+
+ if (ParseKey(is, error) != "x") {
+ *error = "Expected x=";
+ return false;
+ }
+
+ if (!xRange.Parse(is, error)) {
+ return false;
+ }
+
+ if (!SkipChar(is, ',', error)) {
+ return false;
+ }
+
+ if (ParseKey(is, error) != "y") {
+ *error = "Expected y=";
+ return false;
+ }
+
+ if (!yRange.Parse(is, error)) {
+ return false;
+ }
+
+ qValue = 0.5f; // default
+
+ bool gotSar = false;
+ bool gotPar = false;
+ bool gotQ = false;
+
+ while (SkipChar(is, ',', error)) {
+ std::string key = ParseKey(is, error);
+ if (key.empty()) {
+ *error = "Expected key-value";
+ return false;
+ }
+
+ if (key == "sar") {
+ if (gotSar) {
+ *error = "Extra sar parameter";
+ return false;
+ }
+ gotSar = true;
+ if (!sRange.Parse(is, error)) {
+ return false;
+ }
+ } else if (key == "par") {
+ if (gotPar) {
+ *error = "Extra par parameter";
+ return false;
+ }
+ gotPar = true;
+ if (!pRange.Parse(is, error)) {
+ return false;
+ }
+ } else if (key == "q") {
+ if (gotQ) {
+ *error = "Extra q parameter";
+ return false;
+ }
+ gotQ = true;
+ if (!GetQValue(is, &qValue, error)) {
+ return false;
+ }
+ } else {
+ if (!SkipValue(is, error)) {
+ return false;
+ }
+ }
+ }
+
+ return SkipChar(is, ']', error);
+}
+
+void
+SdpImageattrAttributeList::Set::Serialize(std::ostream& os) const
+{
+ os << "[x=";
+ xRange.Serialize(os);
+ os << ",y=";
+ yRange.Serialize(os);
+ if (sRange.IsSet()) {
+ os << ",sar=";
+ sRange.Serialize(os);
+ }
+ if (pRange.IsSet()) {
+ os << ",par=";
+ pRange.Serialize(os);
+ }
+ if (qValue >= 0) {
+ os << std::setprecision(2) << std::fixed << ",q=" << qValue;
+ }
+ os << "]";
+}
+
+bool
+SdpImageattrAttributeList::Imageattr::ParseSets(std::istream& is,
+ std::string* error)
+{
+ std::string type = ParseToken(is, " \t", error);
+
+ bool* isAll = nullptr;
+ std::vector<Set>* sets = nullptr;
+
+ if (type == "send") {
+ isAll = &sendAll;
+ sets = &sendSets;
+ } else if (type == "recv") {
+ isAll = &recvAll;
+ sets = &recvSets;
+ } else {
+ *error = "Unknown type, must be either send or recv";
+ return false;
+ }
+
+ if (*isAll || !sets->empty()) {
+ *error = "Multiple send or recv set lists";
+ return false;
+ }
+
+ is >> std::ws;
+ if (SkipChar(is, '*', error)) {
+ *isAll = true;
+ return true;
+ }
+
+ do {
+ Set set;
+ if (!set.Parse(is, error)) {
+ return false;
+ }
+
+ sets->push_back(set);
+ is >> std::ws;
+ } while (PeekChar(is, error) == '[');
+
+ return true;
+}
+
+bool
+SdpImageattrAttributeList::Imageattr::Parse(std::istream& is,
+ std::string* error)
+{
+ if (!SkipChar(is, '*', error)) {
+ uint16_t value;
+ if (!GetUnsigned<uint16_t>(is, 0, UINT16_MAX, &value, error)) {
+ return false;
+ }
+ pt = Some(value);
+ }
+
+ is >> std::ws;
+ if (!ParseSets(is, error)) {
+ return false;
+ }
+
+ // There might be a second one
+ is >> std::ws;
+ if (is.eof()) {
+ return true;
+ }
+
+ if (!ParseSets(is, error)) {
+ return false;
+ }
+
+ is >> std::ws;
+ if (!is.eof()) {
+ *error = "Trailing characters";
+ return false;
+ }
+
+ return true;
+}
+
+void
+SdpImageattrAttributeList::Imageattr::Serialize(std::ostream& os) const
+{
+ if (pt.isSome()) {
+ os << *pt;
+ } else {
+ os << "*";
+ }
+
+ if (sendAll) {
+ os << " send *";
+ } else if (!sendSets.empty()) {
+ os << " send";
+ for (auto& set : sendSets) {
+ os << " ";
+ set.Serialize(os);
+ }
+ }
+
+ if (recvAll) {
+ os << " recv *";
+ } else if (!recvSets.empty()) {
+ os << " recv";
+ for (auto& set : recvSets) {
+ os << " ";
+ set.Serialize(os);
+ }
+ }
+}
+
+void
+SdpImageattrAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto& imageattr : mImageattrs) {
+ os << "a=" << mType << ":";
+ imageattr.Serialize(os);
+ os << CRLF;
+ }
+}
+
+bool
+SdpImageattrAttributeList::PushEntry(const std::string& raw,
+ std::string* error,
+ size_t* errorPos)
+{
+ std::istringstream is(raw);
+
+ Imageattr imageattr;
+ if (!imageattr.Parse(is, error)) {
+ is.clear();
+ *errorPos = is.tellg();
+ return false;
+ }
+
+ mImageattrs.push_back(imageattr);
+ return true;
+}
+
+void
+SdpMsidAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mMsids.begin(); i != mMsids.end(); ++i) {
+ os << "a=" << mType << ":" << i->identifier;
+ if (i->appdata.length()) {
+ os << " " << i->appdata;
+ }
+ os << CRLF;
+ }
+}
+
+void
+SdpMsidSemanticAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mMsidSemantics.begin(); i != mMsidSemantics.end(); ++i) {
+ os << "a=" << mType << ":" << i->semantic;
+ for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
+ os << " " << *j;
+ }
+ os << CRLF;
+ }
+}
+
+void
+SdpRemoteCandidatesAttribute::Serialize(std::ostream& os) const
+{
+ if (mCandidates.empty()) {
+ return;
+ }
+
+ os << "a=" << mType;
+ for (auto i = mCandidates.begin(); i != mCandidates.end(); i++) {
+ os << (i == mCandidates.begin() ? ":" : " ") << i->id << " " << i->address
+ << " " << i->port;
+ }
+ os << CRLF;
+}
+
+bool
+SdpRidAttributeList::Rid::ParseParameters(std::istream& is, std::string* error)
+{
+ if (!PeekChar(is, error)) {
+ // No parameters
+ return true;
+ }
+
+ do {
+ is >> std::ws;
+ std::string key = ParseKey(is, error);
+ if (key.empty()) {
+ return false; // Illegal trailing cruft
+ }
+
+ // This allows pt= to appear anywhere, instead of only at the beginning, but
+ // this ends up being significantly less code.
+ if (key == "pt") {
+ if (!ParseFormats(is, error)) {
+ return false;
+ }
+ } else if (key == "max-width") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxWidth, error)) {
+ return false;
+ }
+ } else if (key == "max-height") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxHeight, error)) {
+ return false;
+ }
+ } else if (key == "max-fps") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxFps, error)) {
+ return false;
+ }
+ } else if (key == "max-fs") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxFs, error)) {
+ return false;
+ }
+ } else if (key == "max-br") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxBr, error)) {
+ return false;
+ }
+ } else if (key == "max-pps") {
+ if (!GetUnsigned<uint32_t>(
+ is, 0, UINT32_MAX, &constraints.maxPps, error)) {
+ return false;
+ }
+ } else if (key == "depend") {
+ if (!ParseDepend(is, error)) {
+ return false;
+ }
+ } else {
+ (void) ParseToken(is, ";", error);
+ }
+ } while (SkipChar(is, ';', error));
+ return true;
+}
+
+bool
+SdpRidAttributeList::Rid::ParseDepend(
+ std::istream& is,
+ std::string* error)
+{
+ do {
+ std::string id = ParseToken(is, ",;", error);
+ if (id.empty()) {
+ return false;
+ }
+ dependIds.push_back(id);
+ } while(SkipChar(is, ',', error));
+
+ return true;
+}
+
+bool
+SdpRidAttributeList::Rid::ParseFormats(
+ std::istream& is,
+ std::string* error)
+{
+ do {
+ uint16_t fmt;
+ if (!GetUnsigned<uint16_t>(is, 0, 127, &fmt, error)) {
+ return false;
+ }
+ formats.push_back(fmt);
+ } while (SkipChar(is, ',', error));
+
+ return true;
+}
+
+void
+SdpRidAttributeList::Rid::SerializeParameters(std::ostream& os) const
+{
+ if (!HasParameters()) {
+ return;
+ }
+
+ os << " ";
+
+ SkipFirstDelimiter semic(";");
+
+ if (!formats.empty()) {
+ os << semic << "pt=";
+ SkipFirstDelimiter comma(",");
+ for (uint16_t fmt : formats) {
+ os << comma << fmt;
+ }
+ }
+
+ if (constraints.maxWidth) {
+ os << semic << "max-width=" << constraints.maxWidth;
+ }
+
+ if (constraints.maxHeight) {
+ os << semic << "max-height=" << constraints.maxHeight;
+ }
+
+ if (constraints.maxFps) {
+ os << semic << "max-fps=" << constraints.maxFps;
+ }
+
+ if (constraints.maxFs) {
+ os << semic << "max-fs=" << constraints.maxFs;
+ }
+
+ if (constraints.maxBr) {
+ os << semic << "max-br=" << constraints.maxBr;
+ }
+
+ if (constraints.maxPps) {
+ os << semic << "max-pps=" << constraints.maxPps;
+ }
+
+ if (!dependIds.empty()) {
+ os << semic << "depend=";
+ SkipFirstDelimiter comma(",");
+ for (const std::string& id : dependIds) {
+ os << comma << id;
+ }
+ }
+}
+
+bool
+SdpRidAttributeList::Rid::Parse(std::istream& is, std::string* error)
+{
+ id = ParseToken(is, " ", error);
+ if (id.empty()) {
+ return false;
+ }
+
+ is >> std::ws;
+ std::string directionToken = ParseToken(is, " ", error);
+ if (directionToken == "send") {
+ direction = sdp::kSend;
+ } else if (directionToken == "recv") {
+ direction = sdp::kRecv;
+ } else {
+ *error = "Invalid direction, must be either send or recv";
+ return false;
+ }
+
+ return ParseParameters(is, error);
+}
+
+void
+SdpRidAttributeList::Rid::Serialize(std::ostream& os) const
+{
+ os << id << " " << direction;
+ SerializeParameters(os);
+}
+
+bool
+SdpRidAttributeList::Rid::HasFormat(const std::string& format) const
+{
+ uint16_t formatAsInt;
+ if (!SdpHelper::GetPtAsInt(format, &formatAsInt)) {
+ return false;
+ }
+
+ if (formats.empty()) {
+ return true;
+ }
+
+ return (std::find(formats.begin(), formats.end(), formatAsInt) !=
+ formats.end());
+}
+
+void
+SdpRidAttributeList::Serialize(std::ostream& os) const
+{
+ for (const Rid& rid : mRids) {
+ os << "a=" << mType << ":";
+ rid.Serialize(os);
+ os << CRLF;
+ }
+}
+
+bool
+SdpRidAttributeList::PushEntry(const std::string& raw,
+ std::string* error,
+ size_t* errorPos)
+{
+ std::istringstream is(raw);
+
+ Rid rid;
+ if (!rid.Parse(is, error)) {
+ is.clear();
+ *errorPos = is.tellg();
+ return false;
+ }
+
+ mRids.push_back(rid);
+ return true;
+}
+
+void
+SdpRtcpAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mPort;
+ if (!mAddress.empty()) {
+ os << " " << mNetType << " " << mAddrType << " " << mAddress;
+ }
+ os << CRLF;
+}
+
+const char* SdpRtcpFbAttributeList::pli = "pli";
+const char* SdpRtcpFbAttributeList::sli = "sli";
+const char* SdpRtcpFbAttributeList::rpsi = "rpsi";
+const char* SdpRtcpFbAttributeList::app = "app";
+
+const char* SdpRtcpFbAttributeList::fir = "fir";
+const char* SdpRtcpFbAttributeList::tmmbr = "tmmbr";
+const char* SdpRtcpFbAttributeList::tstr = "tstr";
+const char* SdpRtcpFbAttributeList::vbcm = "vbcm";
+
+void
+SdpRtcpFbAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mFeedbacks.begin(); i != mFeedbacks.end(); ++i) {
+ os << "a=" << mType << ":" << i->pt << " " << i->type;
+ if (i->parameter.length()) {
+ os << " " << i->parameter;
+ if (i->extra.length()) {
+ os << " " << i->extra;
+ }
+ }
+ os << CRLF;
+ }
+}
+
+static bool
+ShouldSerializeChannels(SdpRtpmapAttributeList::CodecType type)
+{
+ switch (type) {
+ case SdpRtpmapAttributeList::kOpus:
+ case SdpRtpmapAttributeList::kG722:
+ return true;
+ case SdpRtpmapAttributeList::kPCMU:
+ case SdpRtpmapAttributeList::kPCMA:
+ case SdpRtpmapAttributeList::kVP8:
+ case SdpRtpmapAttributeList::kVP9:
+ case SdpRtpmapAttributeList::kiLBC:
+ case SdpRtpmapAttributeList::kiSAC:
+ case SdpRtpmapAttributeList::kH264:
+ case SdpRtpmapAttributeList::kRed:
+ case SdpRtpmapAttributeList::kUlpfec:
+ case SdpRtpmapAttributeList::kTelephoneEvent:
+ return false;
+ case SdpRtpmapAttributeList::kOtherCodec:
+ return true;
+ }
+ MOZ_CRASH();
+}
+
+void
+SdpRtpmapAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mRtpmaps.begin(); i != mRtpmaps.end(); ++i) {
+ os << "a=" << mType << ":" << i->pt << " " << i->name << "/" << i->clock;
+ if (i->channels && ShouldSerializeChannels(i->codec)) {
+ os << "/" << i->channels;
+ }
+ os << CRLF;
+ }
+}
+
+void
+SdpSctpmapAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mSctpmaps.begin(); i != mSctpmaps.end(); ++i) {
+ os << "a=" << mType << ":" << i->pt << " " << i->name << " " << i->streams
+ << CRLF;
+ }
+}
+
+void
+SdpSetupAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mRole << CRLF;
+}
+
+void
+SdpSimulcastAttribute::Version::Serialize(std::ostream& os) const
+{
+ SkipFirstDelimiter comma(",");
+ for (const std::string& choice : choices) {
+ os << comma << choice;
+ }
+}
+
+bool
+SdpSimulcastAttribute::Version::Parse(std::istream& is, std::string* error)
+{
+ do {
+ std::string value = ParseToken(is, ",; ", error);
+ if (value.empty()) {
+ return false;
+ }
+ choices.push_back(value);
+ } while (SkipChar(is, ',', error));
+
+ return true;
+}
+
+bool
+SdpSimulcastAttribute::Version::GetChoicesAsFormats(
+ std::vector<uint16_t>* formats) const
+{
+ for (const std::string& choice : choices) {
+ uint16_t format;
+ if (!SdpHelper::GetPtAsInt(choice, &format) || (format > 127)) {
+ return false;
+ }
+ formats->push_back(format);
+ }
+
+ return true;
+}
+
+void
+SdpSimulcastAttribute::Versions::Serialize(std::ostream& os) const
+{
+ switch (type) {
+ case kRid:
+ os << "rid=";
+ break;
+ case kPt:
+ os << "pt=";
+ break;
+ }
+
+ SkipFirstDelimiter semic(";");
+ for (const Version& version : *this) {
+ if (!version.IsSet()) {
+ continue;
+ }
+ os << semic;
+ version.Serialize(os);
+ }
+}
+
+bool
+SdpSimulcastAttribute::Versions::Parse(std::istream& is, std::string* error)
+{
+ std::string rawType = ParseKey(is, error);
+ if (rawType.empty()) {
+ return false;
+ }
+
+ if (rawType == "pt") {
+ type = kPt;
+ } else if (rawType == "rid") {
+ type = kRid;
+ } else {
+ *error = "Unknown simulcast identification type ";
+ error->append(rawType);
+ return false;
+ }
+
+ do {
+ Version version;
+ if (!version.Parse(is, error)) {
+ return false;
+ }
+
+ if (type == kPt) {
+ std::vector<uint16_t> formats;
+ if (!version.GetChoicesAsFormats(&formats)) {
+ *error = "Invalid payload type";
+ return false;
+ }
+ }
+
+ push_back(version);
+ } while(SkipChar(is, ';', error));
+
+ return true;
+}
+
+void
+SdpSimulcastAttribute::Serialize(std::ostream& os) const
+{
+ MOZ_ASSERT(sendVersions.IsSet() || recvVersions.IsSet());
+
+ os << "a=" << mType << ":";
+
+ if (sendVersions.IsSet()) {
+ os << " send ";
+ sendVersions.Serialize(os);
+ }
+
+ if (recvVersions.IsSet()) {
+ os << " recv ";
+ recvVersions.Serialize(os);
+ }
+
+ os << CRLF;
+}
+
+bool
+SdpSimulcastAttribute::Parse(std::istream& is, std::string* error)
+{
+ bool gotRecv = false;
+ bool gotSend = false;
+
+ while (true) {
+ is >> std::ws;
+ std::string token = ParseToken(is, " \t", error);
+ if (token.empty()) {
+ break;
+ }
+
+ if (token == "send") {
+ if (gotSend) {
+ *error = "Already got a send list";
+ return false;
+ }
+ gotSend = true;
+
+ is >> std::ws;
+ if (!sendVersions.Parse(is, error)) {
+ return false;
+ }
+ } else if (token == "recv") {
+ if (gotRecv) {
+ *error = "Already got a recv list";
+ return false;
+ }
+ gotRecv = true;
+
+ is >> std::ws;
+ if (!recvVersions.Parse(is, error)) {
+ return false;
+ }
+ } else {
+ *error = "Type must be either 'send' or 'recv'";
+ return false;
+ }
+ }
+
+ if (!gotSend && !gotRecv) {
+ *error = "Empty simulcast attribute";
+ return false;
+ }
+
+ return true;
+}
+
+void
+SdpSsrcAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mSsrcs.begin(); i != mSsrcs.end(); ++i) {
+ os << "a=" << mType << ":" << i->ssrc << " " << i->attribute << CRLF;
+ }
+}
+
+void
+SdpSsrcGroupAttributeList::Serialize(std::ostream& os) const
+{
+ for (auto i = mSsrcGroups.begin(); i != mSsrcGroups.end(); ++i) {
+ os << "a=" << mType << ":" << i->semantics;
+ for (auto j = i->ssrcs.begin(); j != i->ssrcs.end(); ++j) {
+ os << " " << (*j);
+ }
+ os << CRLF;
+ }
+}
+
+void
+SdpMultiStringAttribute::Serialize(std::ostream& os) const
+{
+ for (auto i = mValues.begin(); i != mValues.end(); ++i) {
+ os << "a=" << mType << ":" << *i << CRLF;
+ }
+}
+
+void
+SdpOptionsAttribute::Serialize(std::ostream& os) const
+{
+ if (mValues.empty()) {
+ return;
+ }
+
+ os << "a=" << mType << ":";
+
+ for (auto i = mValues.begin(); i != mValues.end(); ++i) {
+ if (i != mValues.begin()) {
+ os << " ";
+ }
+ os << *i;
+ }
+ os << CRLF;
+}
+
+void
+SdpOptionsAttribute::Load(const std::string& value)
+{
+ size_t start = 0;
+ size_t end = value.find(' ');
+ while (end != std::string::npos) {
+ PushEntry(value.substr(start, end));
+ start = end + 1;
+ end = value.find(' ', start);
+ }
+ PushEntry(value.substr(start));
+}
+
+void
+SdpFlagAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << CRLF;
+}
+
+void
+SdpStringAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mValue << CRLF;
+}
+
+void
+SdpNumberAttribute::Serialize(std::ostream& os) const
+{
+ os << "a=" << mType << ":" << mValue << CRLF;
+}
+
+bool
+SdpAttribute::IsAllowedAtMediaLevel(AttributeType type)
+{
+ switch (type) {
+ case kBundleOnlyAttribute:
+ return true;
+ case kCandidateAttribute:
+ return true;
+ case kConnectionAttribute:
+ return true;
+ case kDirectionAttribute:
+ return true;
+ case kDtlsMessageAttribute:
+ return false;
+ case kEndOfCandidatesAttribute:
+ return true;
+ case kExtmapAttribute:
+ return true;
+ case kFingerprintAttribute:
+ return true;
+ case kFmtpAttribute:
+ return true;
+ case kGroupAttribute:
+ return false;
+ case kIceLiteAttribute:
+ return false;
+ case kIceMismatchAttribute:
+ return true;
+ // RFC 5245 says this is session-level only, but
+ // draft-ietf-mmusic-ice-sip-sdp-03 updates this to allow at the media
+ // level.
+ case kIceOptionsAttribute:
+ return true;
+ case kIcePwdAttribute:
+ return true;
+ case kIceUfragAttribute:
+ return true;
+ case kIdentityAttribute:
+ return false;
+ case kImageattrAttribute:
+ return true;
+ case kInactiveAttribute:
+ return true;
+ case kLabelAttribute:
+ return true;
+ case kMaxptimeAttribute:
+ return true;
+ case kMidAttribute:
+ return true;
+ case kMsidAttribute:
+ return true;
+ case kMsidSemanticAttribute:
+ return false;
+ case kPtimeAttribute:
+ return true;
+ case kRecvonlyAttribute:
+ return true;
+ case kRemoteCandidatesAttribute:
+ return true;
+ case kRidAttribute:
+ return true;
+ case kRtcpAttribute:
+ return true;
+ case kRtcpFbAttribute:
+ return true;
+ case kRtcpMuxAttribute:
+ return true;
+ case kRtcpRsizeAttribute:
+ return true;
+ case kRtpmapAttribute:
+ return true;
+ case kSctpmapAttribute:
+ return true;
+ case kSendonlyAttribute:
+ return true;
+ case kSendrecvAttribute:
+ return true;
+ case kSetupAttribute:
+ return true;
+ case kSimulcastAttribute:
+ return true;
+ case kSsrcAttribute:
+ return true;
+ case kSsrcGroupAttribute:
+ return true;
+ }
+ MOZ_CRASH("Unknown attribute type");
+}
+
+bool
+SdpAttribute::IsAllowedAtSessionLevel(AttributeType type)
+{
+ switch (type) {
+ case kBundleOnlyAttribute:
+ return false;
+ case kCandidateAttribute:
+ return false;
+ case kConnectionAttribute:
+ return true;
+ case kDirectionAttribute:
+ return true;
+ case kDtlsMessageAttribute:
+ return true;
+ case kEndOfCandidatesAttribute:
+ return true;
+ case kExtmapAttribute:
+ return true;
+ case kFingerprintAttribute:
+ return true;
+ case kFmtpAttribute:
+ return false;
+ case kGroupAttribute:
+ return true;
+ case kIceLiteAttribute:
+ return true;
+ case kIceMismatchAttribute:
+ return false;
+ case kIceOptionsAttribute:
+ return true;
+ case kIcePwdAttribute:
+ return true;
+ case kIceUfragAttribute:
+ return true;
+ case kIdentityAttribute:
+ return true;
+ case kImageattrAttribute:
+ return false;
+ case kInactiveAttribute:
+ return true;
+ case kLabelAttribute:
+ return false;
+ case kMaxptimeAttribute:
+ return false;
+ case kMidAttribute:
+ return false;
+ case kMsidSemanticAttribute:
+ return true;
+ case kMsidAttribute:
+ return false;
+ case kPtimeAttribute:
+ return false;
+ case kRecvonlyAttribute:
+ return true;
+ case kRemoteCandidatesAttribute:
+ return false;
+ case kRidAttribute:
+ return false;
+ case kRtcpAttribute:
+ return false;
+ case kRtcpFbAttribute:
+ return false;
+ case kRtcpMuxAttribute:
+ return false;
+ case kRtcpRsizeAttribute:
+ return false;
+ case kRtpmapAttribute:
+ return false;
+ case kSctpmapAttribute:
+ return false;
+ case kSendonlyAttribute:
+ return true;
+ case kSendrecvAttribute:
+ return true;
+ case kSetupAttribute:
+ return true;
+ case kSimulcastAttribute:
+ return false;
+ case kSsrcAttribute:
+ return false;
+ case kSsrcGroupAttribute:
+ return false;
+ }
+ MOZ_CRASH("Unknown attribute type");
+}
+
+const std::string
+SdpAttribute::GetAttributeTypeString(AttributeType type)
+{
+ switch (type) {
+ case kBundleOnlyAttribute:
+ return "bundle-only";
+ case kCandidateAttribute:
+ return "candidate";
+ case kConnectionAttribute:
+ return "connection";
+ case kDtlsMessageAttribute:
+ return "dtls-message";
+ case kEndOfCandidatesAttribute:
+ return "end-of-candidates";
+ case kExtmapAttribute:
+ return "extmap";
+ case kFingerprintAttribute:
+ return "fingerprint";
+ case kFmtpAttribute:
+ return "fmtp";
+ case kGroupAttribute:
+ return "group";
+ case kIceLiteAttribute:
+ return "ice-lite";
+ case kIceMismatchAttribute:
+ return "ice-mismatch";
+ case kIceOptionsAttribute:
+ return "ice-options";
+ case kIcePwdAttribute:
+ return "ice-pwd";
+ case kIceUfragAttribute:
+ return "ice-ufrag";
+ case kIdentityAttribute:
+ return "identity";
+ case kImageattrAttribute:
+ return "imageattr";
+ case kInactiveAttribute:
+ return "inactive";
+ case kLabelAttribute:
+ return "label";
+ case kMaxptimeAttribute:
+ return "maxptime";
+ case kMidAttribute:
+ return "mid";
+ case kMsidAttribute:
+ return "msid";
+ case kMsidSemanticAttribute:
+ return "msid-semantic";
+ case kPtimeAttribute:
+ return "ptime";
+ case kRecvonlyAttribute:
+ return "recvonly";
+ case kRemoteCandidatesAttribute:
+ return "remote-candidates";
+ case kRidAttribute:
+ return "rid";
+ case kRtcpAttribute:
+ return "rtcp";
+ case kRtcpFbAttribute:
+ return "rtcp-fb";
+ case kRtcpMuxAttribute:
+ return "rtcp-mux";
+ case kRtcpRsizeAttribute:
+ return "rtcp-rsize";
+ case kRtpmapAttribute:
+ return "rtpmap";
+ case kSctpmapAttribute:
+ return "sctpmap";
+ case kSendonlyAttribute:
+ return "sendonly";
+ case kSendrecvAttribute:
+ return "sendrecv";
+ case kSetupAttribute:
+ return "setup";
+ case kSimulcastAttribute:
+ return "simulcast";
+ case kSsrcAttribute:
+ return "ssrc";
+ case kSsrcGroupAttribute:
+ return "ssrc-group";
+ case kDirectionAttribute:
+ MOZ_CRASH("kDirectionAttribute not valid here");
+ }
+ MOZ_CRASH("Unknown attribute type");
+}
+
+} // namespace mozilla
diff --git a/media/webrtc/signaling/src/sdp/SdpAttribute.h b/media/webrtc/signaling/src/sdp/SdpAttribute.h
new file mode 100644
index 000000000..d3cf547ff
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpAttribute.h
@@ -0,0 +1,1788 @@
+/* -*- 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 "signaling/src/sdp/SdpEnum.h"
+#include "signaling/src/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,
+ kInactiveAttribute,
+ kLabelAttribute,
+ kMaxptimeAttribute,
+ kMidAttribute,
+ kMsidAttribute,
+ kMsidSemanticAttribute,
+ kPtimeAttribute,
+ kRecvonlyAttribute,
+ kRemoteCandidatesAttribute,
+ kRidAttribute,
+ kRtcpAttribute,
+ kRtcpFbAttribute,
+ kRtcpMuxAttribute,
+ kRtcpRsizeAttribute,
+ kRtpmapAttribute,
+ kSctpmapAttribute,
+ kSendonlyAttribute,
+ kSendrecvAttribute,
+ kSetupAttribute,
+ kSimulcastAttribute,
+ kSsrcAttribute,
+ kSsrcGroupAttribute,
+ kLastAttribute = kSsrcGroupAttribute
+ };
+
+ explicit SdpAttribute(AttributeType type) : mType(type) {}
+ virtual ~SdpAttribute() {}
+
+ 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)
+ {
+ }
+
+ 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)
+ {
+ }
+
+ 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;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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)
+ {}
+
+ 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);
+ }
+
+ virtual void Serialize(std::ostream& os) const override;
+ 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);
+ }
+
+ 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
+ // non-crazy 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);
+ }
+
+ 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;
+ }
+ }
+ }
+
+ 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;
+ bool Parse(std::istream& is, std::string* error);
+ bool ParseAfterBracket(std::istream& is, std::string* error);
+ bool ParseAfterMin(std::istream& is, std::string* error);
+ 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;
+ bool Parse(std::istream& is, std::string* error);
+ bool ParseAfterBracket(std::istream& is, std::string* error);
+ bool ParseAfterMin(std::istream& is, std::string* error);
+ 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;
+ 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;
+ 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;
+ bool Parse(std::istream& is, std::string* error);
+ 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;
+ };
+
+ virtual void Serialize(std::ostream& os) const override;
+ 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);
+ }
+
+ 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);
+ }
+
+ 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)
+ {
+ }
+
+ 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)
+ {}
+
+ bool Parse(std::istream& is, std::string* error);
+ bool ParseParameters(std::istream& is, std::string* error);
+ bool ParseDepend(std::istream& is, std::string* error);
+ 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;
+ };
+
+ virtual void Serialize(std::ostream& os) const override;
+ bool PushEntry(const std::string& raw, std::string* error, size_t* errorPos);
+
+ 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());
+ }
+
+ 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 };
+
+ 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;
+ };
+
+ 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);
+ }
+
+ 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;
+ 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,
+ 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);
+ }
+
+ 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;
+ 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;
+
+ 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]);
+ }
+ }
+
+ std::vector<uint8_t> encodings;
+ };
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+
+ unsigned int max_fs;
+ unsigned int max_fr;
+ };
+
+ class OpusParameters : public Parameters
+ {
+ public:
+ enum { kDefaultMaxPlaybackRate = 48000,
+ kDefaultStereo = 0,
+ kDefaultUseInBandFec = 0 };
+ OpusParameters() :
+ Parameters(SdpRtpmapAttributeList::kOpus),
+ maxplaybackrate(kDefaultMaxPlaybackRate),
+ stereo(kDefaultStereo),
+ useInBandFec(kDefaultUseInBandFec)
+ {}
+
+ Parameters*
+ Clone() const override
+ {
+ return new OpusParameters(*this);
+ }
+
+ void
+ Serialize(std::ostream& os) const override
+ {
+ os << "maxplaybackrate=" << maxplaybackrate
+ << ";stereo=" << stereo
+ << ";useinbandfec=" << useInBandFec;
+ }
+
+ unsigned int maxplaybackrate;
+ unsigned int stereo;
+ unsigned int useInBandFec;
+ };
+
+ 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;
+ }
+
+ std::string dtmfTones;
+ };
+
+ class Fmtp
+ {
+ public:
+ Fmtp(const std::string& aFormat, UniquePtr<Parameters> aParameters)
+ : format(aFormat),
+ parameters(Move(aParameters))
+ {
+ }
+
+ 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;
+ }
+
+ // 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;
+ };
+
+ virtual void Serialize(std::ostream& os) const override;
+
+ void
+ PushEntry(const std::string& format, UniquePtr<Parameters> parameters)
+ {
+ mFmtps.push_back(Fmtp(format, Move(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.
+//
+// (draft-06 is not backward compatabile and draft-07 replaced sctpmap's with
+// fmtp maps - we should carefully choose when to upgrade)
+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);
+ }
+
+ 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&
+ GetEntry(const std::string& pt) const
+ {
+ for (auto it = mSctpmaps.begin(); it != mSctpmaps.end(); ++it) {
+ if (it->pt == pt) {
+ return *it;
+ }
+ }
+ MOZ_CRASH();
+ }
+
+ 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)
+ {
+ }
+
+ 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;
+}
+
+// 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]
+class SdpSimulcastAttribute : public SdpAttribute
+{
+public:
+ SdpSimulcastAttribute() : SdpAttribute(kSimulcastAttribute) {}
+
+ void Serialize(std::ostream& os) const override;
+ bool Parse(std::istream& is, std::string* error);
+
+ class Version
+ {
+ public:
+ void Serialize(std::ostream& os) const;
+ bool IsSet() const
+ {
+ return !choices.empty();
+ }
+ bool Parse(std::istream& is, std::string* error);
+ bool GetChoicesAsFormats(std::vector<uint16_t>* formats) const;
+
+ std::vector<std::string> choices;
+ };
+
+ class Versions : public std::vector<Version>
+ {
+ public:
+ enum Type {
+ kPt,
+ kRid
+ };
+
+ Versions() : type(kRid) {}
+ 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);
+ Type type;
+ };
+
+ 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);
+ }
+
+ 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
+ };
+
+ 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);
+ }
+
+ 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;
+ 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);
+ }
+
+ virtual void Serialize(std::ostream& os) const;
+
+ 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);
+
+ virtual void Serialize(std::ostream& os) const;
+
+ 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) {}
+
+ 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)
+ {
+ }
+
+ 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)
+ {
+ }
+
+ virtual void Serialize(std::ostream& os) const override;
+
+ uint32_t mValue;
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SdpAttributeList.h b/media/webrtc/signaling/src/sdp/SdpAttributeList.h
new file mode 100644
index 000000000..fa84efea6
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpAttributeList.h
@@ -0,0 +1,94 @@
+/* -*- 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 _SDPATTRIBUTELIST_H_
+#define _SDPATTRIBUTELIST_H_
+
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Attributes.h"
+
+#include "signaling/src/sdp/SdpAttribute.h"
+
+namespace mozilla
+{
+
+class SdpAttributeList
+{
+public:
+ virtual ~SdpAttributeList() {}
+ typedef SdpAttribute::AttributeType AttributeType;
+
+ // Avoid default params on virtual functions
+ bool
+ HasAttribute(AttributeType type) const
+ {
+ return HasAttribute(type, true);
+ }
+
+ const SdpAttribute*
+ GetAttribute(AttributeType type) const
+ {
+ return GetAttribute(type, true);
+ }
+
+ virtual bool HasAttribute(AttributeType type, bool sessionFallback) const = 0;
+ virtual const SdpAttribute* GetAttribute(AttributeType type,
+ bool sessionFallback) const = 0;
+ // The setter takes an attribute of any type, and takes ownership
+ virtual void SetAttribute(SdpAttribute* attr) = 0;
+ virtual void RemoveAttribute(AttributeType type) = 0;
+ virtual void Clear() = 0;
+
+ virtual const SdpConnectionAttribute& GetConnection() const = 0;
+ virtual const SdpOptionsAttribute& GetIceOptions() const = 0;
+ virtual const SdpRtcpAttribute& GetRtcp() const = 0;
+ virtual const SdpRemoteCandidatesAttribute& GetRemoteCandidates() const = 0;
+ virtual const SdpSetupAttribute& GetSetup() const = 0;
+ virtual const SdpDtlsMessageAttribute& GetDtlsMessage() const = 0;
+
+ // These attributes can appear multiple times, so the returned
+ // classes actually represent a collection of values.
+ virtual const std::vector<std::string>& GetCandidate() const = 0;
+ virtual const SdpExtmapAttributeList& GetExtmap() const = 0;
+ virtual const SdpFingerprintAttributeList& GetFingerprint() const = 0;
+ virtual const SdpFmtpAttributeList& GetFmtp() const = 0;
+ virtual const SdpGroupAttributeList& GetGroup() const = 0;
+ virtual const SdpImageattrAttributeList& GetImageattr() const = 0;
+ virtual const SdpSimulcastAttribute& GetSimulcast() const = 0;
+ virtual const SdpMsidAttributeList& GetMsid() const = 0;
+ virtual const SdpMsidSemanticAttributeList& GetMsidSemantic() const = 0;
+ virtual const SdpRidAttributeList& GetRid() const = 0;
+ virtual const SdpRtcpFbAttributeList& GetRtcpFb() const = 0;
+ virtual const SdpRtpmapAttributeList& GetRtpmap() const = 0;
+ virtual const SdpSctpmapAttributeList& GetSctpmap() const = 0;
+ virtual const SdpSsrcAttributeList& GetSsrc() const = 0;
+ virtual const SdpSsrcGroupAttributeList& GetSsrcGroup() const = 0;
+
+ // These attributes are effectively simple types, so we'll make life
+ // easy by just returning their value.
+ virtual const std::string& GetIcePwd() const = 0;
+ virtual const std::string& GetIceUfrag() const = 0;
+ virtual const std::string& GetIdentity() const = 0;
+ virtual const std::string& GetLabel() const = 0;
+ virtual unsigned int GetMaxptime() const = 0;
+ virtual const std::string& GetMid() const = 0;
+ virtual unsigned int GetPtime() const = 0;
+
+ // This is "special", because it's multiple things
+ virtual SdpDirectionAttribute::Direction GetDirection() const = 0;
+
+ virtual void Serialize(std::ostream&) const = 0;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const SdpAttributeList& al)
+{
+ al.Serialize(os);
+ return os;
+}
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SdpEnum.h b/media/webrtc/signaling/src/sdp/SdpEnum.h
new file mode 100644
index 000000000..b4a0d16b3
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpEnum.h
@@ -0,0 +1,70 @@
+/* -*- 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 _SDPENUM_H_
+#define _SDPENUM_H_
+
+#include <ostream>
+
+#include "mozilla/Assertions.h"
+
+namespace mozilla
+{
+namespace sdp
+{
+
+enum NetType { kNetTypeNone, kInternet };
+
+inline std::ostream& operator<<(std::ostream& os, sdp::NetType t)
+{
+ switch (t) {
+ case sdp::kNetTypeNone:
+ MOZ_ASSERT(false);
+ return os << "NONE";
+ case sdp::kInternet:
+ return os << "IN";
+ }
+ MOZ_CRASH("Unknown NetType");
+}
+
+enum AddrType { kAddrTypeNone, kIPv4, kIPv6 };
+
+inline std::ostream& operator<<(std::ostream& os, sdp::AddrType t)
+{
+ switch (t) {
+ case sdp::kAddrTypeNone:
+ MOZ_ASSERT(false);
+ return os << "NONE";
+ case sdp::kIPv4:
+ return os << "IP4";
+ case sdp::kIPv6:
+ return os << "IP6";
+ }
+ MOZ_CRASH("Unknown AddrType");
+}
+
+enum Direction {
+ // Start at 1 so these can be used as flags
+ kSend = 1,
+ kRecv = 2
+};
+
+inline std::ostream& operator<<(std::ostream& os, sdp::Direction d)
+{
+ switch (d) {
+ case sdp::kSend:
+ return os << "send";
+ case sdp::kRecv:
+ return os << "recv";
+ }
+ MOZ_CRASH("Unknown Direction");
+}
+
+} // namespace sdp
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SdpErrorHolder.h b/media/webrtc/signaling/src/sdp/SdpErrorHolder.h
new file mode 100644
index 000000000..556fcefb6
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpErrorHolder.h
@@ -0,0 +1,50 @@
+/* -*- 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 _SDPERRORHOLDER_H_
+#define _SDPERRORHOLDER_H_
+
+#include <vector>
+#include <string>
+
+namespace mozilla
+{
+
+class SdpErrorHolder
+{
+public:
+ SdpErrorHolder() {}
+ virtual ~SdpErrorHolder() {}
+
+ void
+ AddParseError(size_t line, const std::string& message)
+ {
+ mErrors.push_back(std::make_pair(line, message));
+ }
+
+ void
+ ClearParseErrors()
+ {
+ mErrors.clear();
+ }
+
+ /**
+ * Returns a reference to the list of parse errors.
+ * This gets cleared out when you call Parse.
+ */
+ const std::vector<std::pair<size_t, std::string> >&
+ GetParseErrors() const
+ {
+ return mErrors;
+ }
+
+private:
+ std::vector<std::pair<size_t, std::string> > mErrors;
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SdpHelper.cpp b/media/webrtc/signaling/src/sdp/SdpHelper.cpp
new file mode 100644
index 000000000..e476b29e5
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpHelper.cpp
@@ -0,0 +1,811 @@
+/* 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/. */
+
+#include "signaling/src/sdp/SdpHelper.h"
+
+#include "signaling/src/sdp/Sdp.h"
+#include "signaling/src/sdp/SdpMediaSection.h"
+#include "logging.h"
+
+#include "nsDebug.h"
+#include "nsError.h"
+#include "prprf.h"
+
+#include <string.h>
+#include <set>
+
+namespace mozilla {
+MOZ_MTLOG_MODULE("sdp")
+
+#define SDP_SET_ERROR(error) \
+ do { \
+ std::ostringstream os; \
+ os << error; \
+ mLastError = os.str(); \
+ MOZ_MTLOG(ML_ERROR, mLastError); \
+ } while (0);
+
+nsresult
+SdpHelper::CopyTransportParams(size_t numComponents,
+ const SdpMediaSection& oldLocal,
+ SdpMediaSection* newLocal)
+{
+ // Copy over m-section details
+ newLocal->SetPort(oldLocal.GetPort());
+ newLocal->GetConnection() = oldLocal.GetConnection();
+
+ const SdpAttributeList& oldLocalAttrs = oldLocal.GetAttributeList();
+ SdpAttributeList& newLocalAttrs = newLocal->GetAttributeList();
+
+ // Now we copy over attributes that won't be added by the usual logic
+ if (oldLocalAttrs.HasAttribute(SdpAttribute::kCandidateAttribute) &&
+ numComponents) {
+ UniquePtr<SdpMultiStringAttribute> candidateAttrs(
+ new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
+ for (const std::string& candidate : oldLocalAttrs.GetCandidate()) {
+ size_t component;
+ nsresult rv = GetComponent(candidate, &component);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (numComponents >= component) {
+ candidateAttrs->mValues.push_back(candidate);
+ }
+ }
+ if (candidateAttrs->mValues.size()) {
+ newLocalAttrs.SetAttribute(candidateAttrs.release());
+ }
+ }
+
+ if (numComponents == 2 &&
+ oldLocalAttrs.HasAttribute(SdpAttribute::kRtcpAttribute)) {
+ // copy rtcp attribute if we had one that we are using
+ newLocalAttrs.SetAttribute(new SdpRtcpAttribute(oldLocalAttrs.GetRtcp()));
+ }
+
+ return NS_OK;
+}
+
+bool
+SdpHelper::AreOldTransportParamsValid(const Sdp& oldAnswer,
+ const Sdp& offerersPreviousSdp,
+ const Sdp& newOffer,
+ size_t level)
+{
+ if (MsectionIsDisabled(oldAnswer.GetMediaSection(level)) ||
+ MsectionIsDisabled(newOffer.GetMediaSection(level))) {
+ // Obvious
+ return false;
+ }
+
+ if (IsBundleSlave(oldAnswer, level)) {
+ // The transport attributes on this m-section were thrown away, because it
+ // was bundled.
+ return false;
+ }
+
+ if (newOffer.GetMediaSection(level).GetAttributeList().HasAttribute(
+ SdpAttribute::kBundleOnlyAttribute) &&
+ IsBundleSlave(newOffer, level)) {
+ // It never makes sense to put transport attributes in a bundle-only
+ // m-section
+ return false;
+ }
+
+ if (IceCredentialsDiffer(newOffer.GetMediaSection(level),
+ offerersPreviousSdp.GetMediaSection(level))) {
+ return false;
+ }
+
+ return true;
+}
+
+bool
+SdpHelper::IceCredentialsDiffer(const SdpMediaSection& msection1,
+ const SdpMediaSection& msection2)
+{
+ const SdpAttributeList& attrs1(msection1.GetAttributeList());
+ const SdpAttributeList& attrs2(msection2.GetAttributeList());
+
+ if ((attrs1.GetIceUfrag() != attrs2.GetIceUfrag()) ||
+ (attrs1.GetIcePwd() != attrs2.GetIcePwd())) {
+ return true;
+ }
+
+ return false;
+}
+
+nsresult
+SdpHelper::GetComponent(const std::string& candidate, size_t* component)
+{
+ unsigned int temp;
+ int32_t result = PR_sscanf(candidate.c_str(), "%*s %u", &temp);
+ if (result == 1) {
+ *component = temp;
+ return NS_OK;
+ }
+ SDP_SET_ERROR("Malformed ICE candidate: " << candidate);
+ return NS_ERROR_INVALID_ARG;
+}
+
+bool
+SdpHelper::MsectionIsDisabled(const SdpMediaSection& msection) const
+{
+ return !msection.GetPort() &&
+ !msection.GetAttributeList().HasAttribute(
+ SdpAttribute::kBundleOnlyAttribute);
+}
+
+void
+SdpHelper::DisableMsection(Sdp* sdp, SdpMediaSection* msection)
+{
+ // Make sure to remove the mid from any group attributes
+ if (msection->GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute)) {
+ std::string mid = msection->GetAttributeList().GetMid();
+ if (sdp->GetAttributeList().HasAttribute(SdpAttribute::kGroupAttribute)) {
+ UniquePtr<SdpGroupAttributeList> newGroupAttr(new SdpGroupAttributeList(
+ sdp->GetAttributeList().GetGroup()));
+ newGroupAttr->RemoveMid(mid);
+ sdp->GetAttributeList().SetAttribute(newGroupAttr.release());
+ }
+ }
+
+ // Clear out attributes.
+ msection->GetAttributeList().Clear();
+
+ auto* direction =
+ new SdpDirectionAttribute(SdpDirectionAttribute::kInactive);
+ msection->GetAttributeList().SetAttribute(direction);
+ msection->SetPort(0);
+
+ msection->ClearCodecs();
+
+ auto mediaType = msection->GetMediaType();
+ switch (mediaType) {
+ case SdpMediaSection::kAudio:
+ msection->AddCodec("0", "PCMU", 8000, 1);
+ break;
+ case SdpMediaSection::kVideo:
+ msection->AddCodec("120", "VP8", 90000, 1);
+ break;
+ case SdpMediaSection::kApplication:
+ msection->AddDataChannel("5000", "rejected", 0);
+ break;
+ default:
+ // We need to have something here to fit the grammar, this seems safe
+ // and 19 is a reserved payload type which should not be used by anyone.
+ msection->AddCodec("19", "reserved", 8000, 1);
+ }
+}
+
+void
+SdpHelper::GetBundleGroups(
+ const Sdp& sdp,
+ std::vector<SdpGroupAttributeList::Group>* bundleGroups) const
+{
+ if (sdp.GetAttributeList().HasAttribute(SdpAttribute::kGroupAttribute)) {
+ for (auto& group : sdp.GetAttributeList().GetGroup().mGroups) {
+ if (group.semantics == SdpGroupAttributeList::kBundle) {
+ bundleGroups->push_back(group);
+ }
+ }
+ }
+}
+
+nsresult
+SdpHelper::GetBundledMids(const Sdp& sdp, BundledMids* bundledMids)
+{
+ std::vector<SdpGroupAttributeList::Group> bundleGroups;
+ GetBundleGroups(sdp, &bundleGroups);
+
+ for (SdpGroupAttributeList::Group& group : bundleGroups) {
+ if (group.tags.empty()) {
+ SDP_SET_ERROR("Empty BUNDLE group");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const SdpMediaSection* masterBundleMsection(
+ FindMsectionByMid(sdp, group.tags[0]));
+
+ if (!masterBundleMsection) {
+ SDP_SET_ERROR("mid specified for bundle transport in group attribute"
+ " does not exist in the SDP. (mid=" << group.tags[0] << ")");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (MsectionIsDisabled(*masterBundleMsection)) {
+ SDP_SET_ERROR("mid specified for bundle transport in group attribute"
+ " points at a disabled m-section. (mid=" << group.tags[0] << ")");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ for (const std::string& mid : group.tags) {
+ if (bundledMids->count(mid)) {
+ SDP_SET_ERROR("mid \'" << mid << "\' appears more than once in a "
+ "BUNDLE group");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ (*bundledMids)[mid] = masterBundleMsection;
+ }
+ }
+
+ return NS_OK;
+}
+
+bool
+SdpHelper::IsBundleSlave(const Sdp& sdp, uint16_t level)
+{
+ auto& msection = sdp.GetMediaSection(level);
+
+ if (!msection.GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute)) {
+ // No mid, definitely no bundle for this m-section
+ return false;
+ }
+ std::string mid(msection.GetAttributeList().GetMid());
+
+ BundledMids bundledMids;
+ nsresult rv = GetBundledMids(sdp, &bundledMids);
+ if (NS_FAILED(rv)) {
+ // Should have been caught sooner.
+ MOZ_ASSERT(false);
+ return false;
+ }
+
+ if (bundledMids.count(mid) && level != bundledMids[mid]->GetLevel()) {
+ // mid is bundled, and isn't the bundle m-section
+ return true;
+ }
+
+ return false;
+}
+
+nsresult
+SdpHelper::GetMidFromLevel(const Sdp& sdp,
+ uint16_t level,
+ std::string* mid)
+{
+ if (level >= sdp.GetMediaSectionCount()) {
+ SDP_SET_ERROR("Index " << level << " out of range");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ const SdpMediaSection& msection = sdp.GetMediaSection(level);
+ const SdpAttributeList& attrList = msection.GetAttributeList();
+
+ // grab the mid and set the outparam
+ if (attrList.HasAttribute(SdpAttribute::kMidAttribute)) {
+ *mid = attrList.GetMid();
+ }
+
+ return NS_OK;
+}
+
+nsresult
+SdpHelper::AddCandidateToSdp(Sdp* sdp,
+ const std::string& candidateUntrimmed,
+ const std::string& mid,
+ uint16_t level)
+{
+
+ if (level >= sdp->GetMediaSectionCount()) {
+ SDP_SET_ERROR("Index " << level << " out of range");
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Trim off '[a=]candidate:'
+ size_t begin = candidateUntrimmed.find(':');
+ if (begin == std::string::npos) {
+ SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")");
+ return NS_ERROR_INVALID_ARG;
+ }
+ ++begin;
+
+ std::string candidate = candidateUntrimmed.substr(begin);
+
+ // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-11#section-3.4.2.1
+ // Implementations receiving an ICE Candidate object MUST use the MID if
+ // present, or the m= line index, if not (as it could have come from a
+ // non-JSEP endpoint). (bug 1095793)
+ SdpMediaSection* msection = 0;
+ if (!mid.empty()) {
+ // FindMsectionByMid could return nullptr
+ msection = FindMsectionByMid(*sdp, mid);
+
+ // Check to make sure mid matches what we'd get by
+ // looking up the m= line using the level. (mjf)
+ std::string checkMid;
+ nsresult rv = GetMidFromLevel(*sdp, level, &checkMid);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (mid != checkMid) {
+ SDP_SET_ERROR("Mismatch between mid and level - \"" << mid
+ << "\" is not the mid for level " << level
+ << "; \"" << checkMid << "\" is");
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+ if (!msection) {
+ msection = &(sdp->GetMediaSection(level));
+ }
+
+ SdpAttributeList& attrList = msection->GetAttributeList();
+
+ UniquePtr<SdpMultiStringAttribute> candidates;
+ if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) {
+ // Create new
+ candidates.reset(
+ new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
+ } else {
+ // Copy existing
+ candidates.reset(new SdpMultiStringAttribute(
+ *static_cast<const SdpMultiStringAttribute*>(
+ attrList.GetAttribute(SdpAttribute::kCandidateAttribute))));
+ }
+ candidates->PushEntry(candidate);
+ attrList.SetAttribute(candidates.release());
+
+ return NS_OK;
+}
+
+void
+SdpHelper::SetIceGatheringComplete(Sdp* sdp,
+ uint16_t level,
+ BundledMids bundledMids)
+{
+ SdpMediaSection& msection = sdp->GetMediaSection(level);
+
+ if (kSlaveBundle == GetMsectionBundleType(*sdp,
+ level,
+ bundledMids,
+ nullptr)) {
+ return; // Slave bundle m-section. Skip.
+ }
+
+ SdpAttributeList& attrs = msection.GetAttributeList();
+ attrs.SetAttribute(
+ new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
+ // Remove trickle-ice option
+ attrs.RemoveAttribute(SdpAttribute::kIceOptionsAttribute);
+}
+
+void
+SdpHelper::SetDefaultAddresses(const std::string& defaultCandidateAddr,
+ uint16_t defaultCandidatePort,
+ const std::string& defaultRtcpCandidateAddr,
+ uint16_t defaultRtcpCandidatePort,
+ Sdp* sdp,
+ uint16_t level,
+ BundledMids bundledMids)
+{
+ SdpMediaSection& msection = sdp->GetMediaSection(level);
+ std::string masterMid;
+
+ MsectionBundleType bundleType = GetMsectionBundleType(*sdp,
+ level,
+ bundledMids,
+ &masterMid);
+ if (kSlaveBundle == bundleType) {
+ return; // Slave bundle m-section. Skip.
+ }
+ if (kMasterBundle == bundleType) {
+ // Master bundle m-section. Set defaultCandidateAddr and
+ // defaultCandidatePort on all bundled m-sections.
+ const SdpMediaSection* masterBundleMsection(bundledMids[masterMid]);
+ for (auto i = bundledMids.begin(); i != bundledMids.end(); ++i) {
+ if (i->second != masterBundleMsection) {
+ continue;
+ }
+ SdpMediaSection* bundledMsection = FindMsectionByMid(*sdp, i->first);
+ if (!bundledMsection) {
+ MOZ_ASSERT(false);
+ continue;
+ }
+ SetDefaultAddresses(defaultCandidateAddr,
+ defaultCandidatePort,
+ defaultRtcpCandidateAddr,
+ defaultRtcpCandidatePort,
+ bundledMsection);
+ }
+ }
+
+ SetDefaultAddresses(defaultCandidateAddr,
+ defaultCandidatePort,
+ defaultRtcpCandidateAddr,
+ defaultRtcpCandidatePort,
+ &msection);
+}
+
+void
+SdpHelper::SetDefaultAddresses(const std::string& defaultCandidateAddr,
+ uint16_t defaultCandidatePort,
+ const std::string& defaultRtcpCandidateAddr,
+ uint16_t defaultRtcpCandidatePort,
+ SdpMediaSection* msection)
+{
+ msection->GetConnection().SetAddress(defaultCandidateAddr);
+ msection->SetPort(defaultCandidatePort);
+
+ if (!defaultRtcpCandidateAddr.empty()) {
+ sdp::AddrType ipVersion = sdp::kIPv4;
+ if (defaultRtcpCandidateAddr.find(':') != std::string::npos) {
+ ipVersion = sdp::kIPv6;
+ }
+ msection->GetAttributeList().SetAttribute(new SdpRtcpAttribute(
+ defaultRtcpCandidatePort,
+ sdp::kInternet,
+ ipVersion,
+ defaultRtcpCandidateAddr));
+ }
+}
+
+nsresult
+SdpHelper::GetIdsFromMsid(const Sdp& sdp,
+ const SdpMediaSection& msection,
+ std::string* streamId,
+ std::string* trackId)
+{
+ if (!sdp.GetAttributeList().HasAttribute(
+ SdpAttribute::kMsidSemanticAttribute)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ auto& msidSemantics = sdp.GetAttributeList().GetMsidSemantic().mMsidSemantics;
+ std::vector<SdpMsidAttributeList::Msid> allMsids;
+ nsresult rv = GetMsids(msection, &allMsids);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool allMsidsAreWebrtc = false;
+ std::set<std::string> webrtcMsids;
+
+ for (auto i = msidSemantics.begin(); i != msidSemantics.end(); ++i) {
+ if (i->semantic == "WMS") {
+ for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
+ if (*j == "*") {
+ allMsidsAreWebrtc = true;
+ } else {
+ webrtcMsids.insert(*j);
+ }
+ }
+ break;
+ }
+ }
+
+ bool found = false;
+
+ for (auto i = allMsids.begin(); i != allMsids.end(); ++i) {
+ if (allMsidsAreWebrtc || webrtcMsids.count(i->identifier)) {
+ if (i->appdata.empty()) {
+ SDP_SET_ERROR("Invalid webrtc msid at level " << msection.GetLevel()
+ << ": Missing track id.");
+ return NS_ERROR_INVALID_ARG;
+ }
+ if (!found) {
+ *streamId = i->identifier;
+ *trackId = i->appdata;
+ found = true;
+ } else if ((*streamId != i->identifier) || (*trackId != i->appdata)) {
+ SDP_SET_ERROR("Found multiple different webrtc msids in m-section "
+ << msection.GetLevel() << ". The behavior here is "
+ "undefined.");
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+ }
+
+ if (!found) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+SdpHelper::GetMsids(const SdpMediaSection& msection,
+ std::vector<SdpMsidAttributeList::Msid>* msids)
+{
+ if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMsidAttribute)) {
+ *msids = msection.GetAttributeList().GetMsid().mMsids;
+ }
+
+ // Can we find some additional msids in ssrc attributes?
+ // (Chrome does not put plain-old msid attributes in its SDP)
+ if (msection.GetAttributeList().HasAttribute(SdpAttribute::kSsrcAttribute)) {
+ auto& ssrcs = msection.GetAttributeList().GetSsrc().mSsrcs;
+
+ for (auto i = ssrcs.begin(); i != ssrcs.end(); ++i) {
+ if (i->attribute.find("msid:") == 0) {
+ std::string streamId;
+ std::string trackId;
+ nsresult rv = ParseMsid(i->attribute, &streamId, &trackId);
+ NS_ENSURE_SUCCESS(rv, rv);
+ msids->push_back({streamId, trackId});
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+nsresult
+SdpHelper::ParseMsid(const std::string& msidAttribute,
+ std::string* streamId,
+ std::string* trackId)
+{
+ // Would be nice if SdpSsrcAttributeList could parse out the contained
+ // attribute, but at least the parse here is simple.
+ // We are being very forgiving here wrt whitespace; tabs are not actually
+ // allowed, nor is leading/trailing whitespace.
+ size_t streamIdStart = msidAttribute.find_first_not_of(" \t", 5);
+ // We do not assume the appdata token is here, since this is not
+ // necessarily a webrtc msid
+ if (streamIdStart == std::string::npos) {
+ SDP_SET_ERROR("Malformed source-level msid attribute: "
+ << msidAttribute);
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ size_t streamIdEnd = msidAttribute.find_first_of(" \t", streamIdStart);
+ if (streamIdEnd == std::string::npos) {
+ streamIdEnd = msidAttribute.size();
+ }
+
+ size_t trackIdStart =
+ msidAttribute.find_first_not_of(" \t", streamIdEnd);
+ if (trackIdStart == std::string::npos) {
+ trackIdStart = msidAttribute.size();
+ }
+
+ size_t trackIdEnd = msidAttribute.find_first_of(" \t", trackIdStart);
+ if (trackIdEnd == std::string::npos) {
+ trackIdEnd = msidAttribute.size();
+ }
+
+ size_t streamIdSize = streamIdEnd - streamIdStart;
+ size_t trackIdSize = trackIdEnd - trackIdStart;
+
+ *streamId = msidAttribute.substr(streamIdStart, streamIdSize);
+ *trackId = msidAttribute.substr(trackIdStart, trackIdSize);
+ return NS_OK;
+}
+
+void
+SdpHelper::SetupMsidSemantic(const std::vector<std::string>& msids,
+ Sdp* sdp) const
+{
+ if (!msids.empty()) {
+ UniquePtr<SdpMsidSemanticAttributeList> msidSemantics(
+ new SdpMsidSemanticAttributeList);
+ msidSemantics->PushEntry("WMS", msids);
+ sdp->GetAttributeList().SetAttribute(msidSemantics.release());
+ }
+}
+
+std::string
+SdpHelper::GetCNAME(const SdpMediaSection& msection) const
+{
+ if (msection.GetAttributeList().HasAttribute(SdpAttribute::kSsrcAttribute)) {
+ auto& ssrcs = msection.GetAttributeList().GetSsrc().mSsrcs;
+ for (auto i = ssrcs.begin(); i != ssrcs.end(); ++i) {
+ if (i->attribute.find("cname:") == 0) {
+ return i->attribute.substr(6);
+ }
+ }
+ }
+ return "";
+}
+
+const SdpMediaSection*
+SdpHelper::FindMsectionByMid(const Sdp& sdp,
+ const std::string& mid) const
+{
+ for (size_t i = 0; i < sdp.GetMediaSectionCount(); ++i) {
+ auto& attrs = sdp.GetMediaSection(i).GetAttributeList();
+ if (attrs.HasAttribute(SdpAttribute::kMidAttribute) &&
+ attrs.GetMid() == mid) {
+ return &sdp.GetMediaSection(i);
+ }
+ }
+ return nullptr;
+}
+
+SdpMediaSection*
+SdpHelper::FindMsectionByMid(Sdp& sdp,
+ const std::string& mid) const
+{
+ for (size_t i = 0; i < sdp.GetMediaSectionCount(); ++i) {
+ auto& attrs = sdp.GetMediaSection(i).GetAttributeList();
+ if (attrs.HasAttribute(SdpAttribute::kMidAttribute) &&
+ attrs.GetMid() == mid) {
+ return &sdp.GetMediaSection(i);
+ }
+ }
+ return nullptr;
+}
+
+nsresult
+SdpHelper::CopyStickyParams(const SdpMediaSection& source,
+ SdpMediaSection* dest)
+{
+ auto& sourceAttrs = source.GetAttributeList();
+ auto& destAttrs = dest->GetAttributeList();
+
+ // There's no reason to renegotiate rtcp-mux
+ if (sourceAttrs.HasAttribute(SdpAttribute::kRtcpMuxAttribute)) {
+ destAttrs.SetAttribute(
+ new SdpFlagAttribute(SdpAttribute::kRtcpMuxAttribute));
+ }
+
+ // mid should stay the same
+ if (sourceAttrs.HasAttribute(SdpAttribute::kMidAttribute)) {
+ destAttrs.SetAttribute(
+ new SdpStringAttribute(SdpAttribute::kMidAttribute,
+ sourceAttrs.GetMid()));
+ }
+
+ return NS_OK;
+}
+
+bool
+SdpHelper::HasRtcp(SdpMediaSection::Protocol proto) const
+{
+ switch (proto) {
+ case SdpMediaSection::kRtpAvpf:
+ case SdpMediaSection::kDccpRtpAvpf:
+ case SdpMediaSection::kDccpRtpSavpf:
+ case SdpMediaSection::kRtpSavpf:
+ case SdpMediaSection::kUdpTlsRtpSavpf:
+ case SdpMediaSection::kTcpTlsRtpSavpf:
+ case SdpMediaSection::kDccpTlsRtpSavpf:
+ return true;
+ case SdpMediaSection::kRtpAvp:
+ case SdpMediaSection::kUdp:
+ case SdpMediaSection::kVat:
+ case SdpMediaSection::kRtp:
+ case SdpMediaSection::kUdptl:
+ case SdpMediaSection::kTcp:
+ case SdpMediaSection::kTcpRtpAvp:
+ case SdpMediaSection::kRtpSavp:
+ case SdpMediaSection::kTcpBfcp:
+ case SdpMediaSection::kTcpTlsBfcp:
+ case SdpMediaSection::kTcpTls:
+ case SdpMediaSection::kFluteUdp:
+ case SdpMediaSection::kTcpMsrp:
+ case SdpMediaSection::kTcpTlsMsrp:
+ case SdpMediaSection::kDccp:
+ case SdpMediaSection::kDccpRtpAvp:
+ case SdpMediaSection::kDccpRtpSavp:
+ case SdpMediaSection::kUdpTlsRtpSavp:
+ case SdpMediaSection::kTcpTlsRtpSavp:
+ case SdpMediaSection::kDccpTlsRtpSavp:
+ case SdpMediaSection::kUdpMbmsFecRtpAvp:
+ case SdpMediaSection::kUdpMbmsFecRtpSavp:
+ case SdpMediaSection::kUdpMbmsRepair:
+ case SdpMediaSection::kFecUdp:
+ case SdpMediaSection::kUdpFec:
+ case SdpMediaSection::kTcpMrcpv2:
+ case SdpMediaSection::kTcpTlsMrcpv2:
+ case SdpMediaSection::kPstn:
+ case SdpMediaSection::kUdpTlsUdptl:
+ case SdpMediaSection::kSctp:
+ case SdpMediaSection::kSctpDtls:
+ case SdpMediaSection::kDtlsSctp:
+ return false;
+ }
+ MOZ_CRASH("Unknown protocol, probably corruption.");
+}
+
+SdpMediaSection::Protocol
+SdpHelper::GetProtocolForMediaType(SdpMediaSection::MediaType type)
+{
+ if (type == SdpMediaSection::kApplication) {
+ return SdpMediaSection::kDtlsSctp;
+ }
+
+ return SdpMediaSection::kUdpTlsRtpSavpf;
+}
+
+void
+SdpHelper::appendSdpParseErrors(
+ const std::vector<std::pair<size_t, std::string> >& aErrors,
+ std::string* aErrorString)
+{
+ std::ostringstream os;
+ for (auto i = aErrors.begin(); i != aErrors.end(); ++i) {
+ os << "SDP Parse Error on line " << i->first << ": " + i->second
+ << std::endl;
+ }
+ *aErrorString += os.str();
+}
+
+/* static */ bool
+SdpHelper::GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam)
+{
+ char* end;
+ unsigned long pt = strtoul(ptString.c_str(), &end, 10);
+ size_t length = static_cast<size_t>(end - ptString.c_str());
+ if ((pt > UINT16_MAX) || (length != ptString.size())) {
+ return false;
+ }
+ *ptOutparam = pt;
+ return true;
+}
+
+void
+SdpHelper::AddCommonExtmaps(
+ const SdpMediaSection& remoteMsection,
+ const std::vector<SdpExtmapAttributeList::Extmap>& localExtensions,
+ SdpMediaSection* localMsection)
+{
+ if (!remoteMsection.GetAttributeList().HasAttribute(
+ SdpAttribute::kExtmapAttribute)) {
+ return;
+ }
+
+ UniquePtr<SdpExtmapAttributeList> localExtmap(new SdpExtmapAttributeList);
+ auto& theirExtmap = remoteMsection.GetAttributeList().GetExtmap().mExtmaps;
+ for (auto i = theirExtmap.begin(); i != theirExtmap.end(); ++i) {
+ for (auto j = localExtensions.begin(); j != localExtensions.end(); ++j) {
+ // verify we have a valid combination of directions. For kInactive
+ // we'll just not add the response
+ if (i->extensionname == j->extensionname &&
+ (((i->direction == SdpDirectionAttribute::Direction::kSendrecv ||
+ i->direction == SdpDirectionAttribute::Direction::kSendonly) &&
+ (j->direction == SdpDirectionAttribute::Direction::kSendrecv ||
+ j->direction == SdpDirectionAttribute::Direction::kRecvonly)) ||
+
+ ((i->direction == SdpDirectionAttribute::Direction::kSendrecv ||
+ i->direction == SdpDirectionAttribute::Direction::kRecvonly) &&
+ (j->direction == SdpDirectionAttribute::Direction::kSendrecv ||
+ j->direction == SdpDirectionAttribute::Direction::kSendonly)))) {
+ auto k = *i; // we need to modify it
+ if (j->direction == SdpDirectionAttribute::Direction::kSendonly) {
+ k.direction = SdpDirectionAttribute::Direction::kRecvonly;
+ } else if (j->direction == SdpDirectionAttribute::Direction::kRecvonly) {
+ k.direction = SdpDirectionAttribute::Direction::kSendonly;
+ }
+ localExtmap->mExtmaps.push_back(k);
+
+ // RFC 5285 says that ids >= 4096 can be used by the offerer to
+ // force the answerer to pick, otherwise the value in the offer is
+ // used.
+ if (localExtmap->mExtmaps.back().entry >= 4096) {
+ localExtmap->mExtmaps.back().entry = j->entry;
+ }
+ }
+ }
+ }
+
+ if (!localExtmap->mExtmaps.empty()) {
+ localMsection->GetAttributeList().SetAttribute(localExtmap.release());
+ }
+}
+
+SdpHelper::MsectionBundleType
+SdpHelper::GetMsectionBundleType(const Sdp& sdp,
+ uint16_t level,
+ BundledMids& bundledMids,
+ std::string* masterMid) const
+{
+ const SdpMediaSection& msection = sdp.GetMediaSection(level);
+ if (msection.GetAttributeList().HasAttribute(SdpAttribute::kMidAttribute)) {
+ std::string mid(msection.GetAttributeList().GetMid());
+ if (bundledMids.count(mid)) {
+ const SdpMediaSection* masterBundleMsection(bundledMids[mid]);
+ if (msection.GetLevel() != masterBundleMsection->GetLevel()) {
+ return kSlaveBundle;
+ }
+
+ // allow the caller not to care about the masterMid
+ if (masterMid) {
+ *masterMid = mid;
+ }
+ return kMasterBundle;
+ }
+ }
+ return kNoBundle;
+}
+
+} // namespace mozilla
+
+
diff --git a/media/webrtc/signaling/src/sdp/SdpHelper.h b/media/webrtc/signaling/src/sdp/SdpHelper.h
new file mode 100644
index 000000000..21940f280
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpHelper.h
@@ -0,0 +1,131 @@
+/* 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 _SDPHELPER_H_
+#define _SDPHELPER_H_
+
+#include "nsError.h"
+
+#include "signaling/src/sdp/SdpMediaSection.h"
+#include "signaling/src/sdp/SdpAttribute.h"
+
+#include "m_cpp_utils.h"
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace mozilla {
+class SdpMediaSection;
+class Sdp;
+
+class SdpHelper {
+ public:
+ enum MsectionBundleType {
+ kNoBundle,
+ kSlaveBundle,
+ kMasterBundle
+ };
+
+ // Takes a std::string* into which error strings will be written for the
+ // lifetime of the SdpHelper.
+ explicit SdpHelper(std::string* errorDest) : mLastError(*errorDest) {}
+ ~SdpHelper() {}
+
+ nsresult GetComponent(const std::string& candidate, size_t* component);
+ nsresult CopyTransportParams(size_t numComponents,
+ const SdpMediaSection& source,
+ SdpMediaSection* dest);
+ bool AreOldTransportParamsValid(const Sdp& oldAnswer,
+ const Sdp& offerersPreviousSdp,
+ const Sdp& newOffer,
+ size_t level);
+ bool IceCredentialsDiffer(const SdpMediaSection& msection1,
+ const SdpMediaSection& msection2);
+
+ bool MsectionIsDisabled(const SdpMediaSection& msection) const;
+ static void DisableMsection(Sdp* sdp, SdpMediaSection* msection);
+
+ // Maps each mid to the m-section that is the master of its bundle.
+ // Mids that do not appear in an a=group:BUNDLE do not appear here.
+ typedef std::map<std::string, const SdpMediaSection*> BundledMids;
+
+ nsresult GetBundledMids(const Sdp& sdp, BundledMids* bundledMids);
+
+ bool IsBundleSlave(const Sdp& localSdp, uint16_t level);
+ void GetBundleGroups(
+ const Sdp& sdp,
+ std::vector<SdpGroupAttributeList::Group>* groups) const;
+
+ nsresult GetMidFromLevel(const Sdp& sdp,
+ uint16_t level,
+ std::string* mid);
+ nsresult GetIdsFromMsid(const Sdp& sdp,
+ const SdpMediaSection& msection,
+ std::string* streamId,
+ std::string* trackId);
+ nsresult GetMsids(const SdpMediaSection& msection,
+ std::vector<SdpMsidAttributeList::Msid>* msids);
+ nsresult ParseMsid(const std::string& msidAttribute,
+ std::string* streamId,
+ std::string* trackId);
+ nsresult AddCandidateToSdp(Sdp* sdp,
+ const std::string& candidate,
+ const std::string& mid,
+ uint16_t level);
+ void SetIceGatheringComplete(Sdp* sdp,
+ uint16_t level,
+ BundledMids bundledMids);
+ void SetDefaultAddresses(const std::string& defaultCandidateAddr,
+ uint16_t defaultCandidatePort,
+ const std::string& defaultRtcpCandidateAddr,
+ uint16_t defaultRtcpCandidatePort,
+ Sdp* sdp,
+ uint16_t level,
+ BundledMids bundledMids);
+ void SetDefaultAddresses(const std::string& defaultCandidateAddr,
+ uint16_t defaultCandidatePort,
+ const std::string& defaultRtcpCandidateAddr,
+ uint16_t defaultRtcpCandidatePort,
+ SdpMediaSection* msection);
+ void SetupMsidSemantic(const std::vector<std::string>& msids,
+ Sdp* sdp) const;
+ MsectionBundleType GetMsectionBundleType(const Sdp& sdp,
+ uint16_t level,
+ BundledMids& bundledMids,
+ std::string* masterMid) const;
+
+ std::string GetCNAME(const SdpMediaSection& msection) const;
+
+ SdpMediaSection* FindMsectionByMid(Sdp& sdp,
+ const std::string& mid) const;
+
+ const SdpMediaSection* FindMsectionByMid(const Sdp& sdp,
+ const std::string& mid) const;
+
+ nsresult CopyStickyParams(const SdpMediaSection& source,
+ SdpMediaSection* dest);
+ bool HasRtcp(SdpMediaSection::Protocol proto) const;
+ static SdpMediaSection::Protocol GetProtocolForMediaType(
+ SdpMediaSection::MediaType type);
+ void appendSdpParseErrors(
+ const std::vector<std::pair<size_t, std::string> >& aErrors,
+ std::string* aErrorString);
+
+ static bool GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam);
+
+ void AddCommonExtmaps(
+ const SdpMediaSection& remoteMsection,
+ const std::vector<SdpExtmapAttributeList::Extmap>& localExtensions,
+ SdpMediaSection* localMsection);
+
+ private:
+ std::string& mLastError;
+
+ DISALLOW_COPY_ASSIGN(SdpHelper);
+};
+} // namespace mozilla
+
+#endif // _SDPHELPER_H_
+
diff --git a/media/webrtc/signaling/src/sdp/SdpMediaSection.cpp b/media/webrtc/signaling/src/sdp/SdpMediaSection.cpp
new file mode 100644
index 000000000..bd3fab555
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.cpp
@@ -0,0 +1,196 @@
+/* -*- 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/. */
+
+#include "signaling/src/sdp/SdpMediaSection.h"
+
+namespace mozilla
+{
+const SdpFmtpAttributeList::Parameters*
+SdpMediaSection::FindFmtp(const std::string& pt) const
+{
+ const SdpAttributeList& attrs = GetAttributeList();
+
+ if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) {
+ for (auto& fmtpAttr : attrs.GetFmtp().mFmtps) {
+ if (fmtpAttr.format == pt && fmtpAttr.parameters) {
+ return fmtpAttr.parameters.get();
+ }
+ }
+ }
+ return nullptr;
+}
+
+void
+SdpMediaSection::SetFmtp(const SdpFmtpAttributeList::Fmtp& fmtpToSet)
+{
+ UniquePtr<SdpFmtpAttributeList> fmtps(new SdpFmtpAttributeList);
+
+ if (GetAttributeList().HasAttribute(SdpAttribute::kFmtpAttribute)) {
+ *fmtps = GetAttributeList().GetFmtp();
+ }
+
+ bool found = false;
+ for (SdpFmtpAttributeList::Fmtp& fmtp : fmtps->mFmtps) {
+ if (fmtp.format == fmtpToSet.format) {
+ fmtp = fmtpToSet;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ fmtps->mFmtps.push_back(fmtpToSet);
+ }
+
+ GetAttributeList().SetAttribute(fmtps.release());
+}
+
+void
+SdpMediaSection::RemoveFmtp(const std::string& pt)
+{
+ UniquePtr<SdpFmtpAttributeList> fmtps(new SdpFmtpAttributeList);
+
+ SdpAttributeList& attrList = GetAttributeList();
+ if (attrList.HasAttribute(SdpAttribute::kFmtpAttribute)) {
+ *fmtps = attrList.GetFmtp();
+ }
+
+ for (size_t i = 0; i < fmtps->mFmtps.size(); ++i) {
+ if (pt == fmtps->mFmtps[i].format) {
+ fmtps->mFmtps.erase(fmtps->mFmtps.begin() + i);
+ break;
+ }
+ }
+
+ attrList.SetAttribute(fmtps.release());
+}
+
+const SdpRtpmapAttributeList::Rtpmap*
+SdpMediaSection::FindRtpmap(const std::string& pt) const
+{
+ auto& attrs = GetAttributeList();
+ if (!attrs.HasAttribute(SdpAttribute::kRtpmapAttribute)) {
+ return nullptr;
+ }
+
+ const SdpRtpmapAttributeList& rtpmap = attrs.GetRtpmap();
+ if (!rtpmap.HasEntry(pt)) {
+ return nullptr;
+ }
+
+ return &rtpmap.GetEntry(pt);
+}
+
+const SdpSctpmapAttributeList::Sctpmap*
+SdpMediaSection::FindSctpmap(const std::string& pt) const
+{
+ auto& attrs = GetAttributeList();
+ if (!attrs.HasAttribute(SdpAttribute::kSctpmapAttribute)) {
+ return nullptr;
+ }
+
+ const SdpSctpmapAttributeList& sctpmap = attrs.GetSctpmap();
+ if (!sctpmap.HasEntry(pt)) {
+ return nullptr;
+ }
+
+ return &sctpmap.GetEntry(pt);
+}
+
+bool
+SdpMediaSection::HasRtcpFb(const std::string& pt,
+ SdpRtcpFbAttributeList::Type type,
+ const std::string& subType) const
+{
+ const SdpAttributeList& attrs(GetAttributeList());
+
+ if (!attrs.HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
+ return false;
+ }
+
+ for (auto& rtcpfb : attrs.GetRtcpFb().mFeedbacks) {
+ if (rtcpfb.type == type) {
+ if (rtcpfb.pt == "*" || rtcpfb.pt == pt) {
+ if (rtcpfb.parameter == subType) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+SdpRtcpFbAttributeList
+SdpMediaSection::GetRtcpFbs() const
+{
+ SdpRtcpFbAttributeList result;
+ if (GetAttributeList().HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
+ result = GetAttributeList().GetRtcpFb();
+ }
+ return result;
+}
+
+void
+SdpMediaSection::SetRtcpFbs(const SdpRtcpFbAttributeList& rtcpfbs)
+{
+ if (rtcpfbs.mFeedbacks.empty()) {
+ GetAttributeList().RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
+ return;
+ }
+
+ GetAttributeList().SetAttribute(new SdpRtcpFbAttributeList(rtcpfbs));
+}
+
+void
+SdpMediaSection::SetSsrcs(const std::vector<uint32_t>& ssrcs,
+ const std::string& cname)
+{
+ if (ssrcs.empty()) {
+ GetAttributeList().RemoveAttribute(SdpAttribute::kSsrcAttribute);
+ return;
+ }
+
+ UniquePtr<SdpSsrcAttributeList> ssrcAttr(new SdpSsrcAttributeList);
+ for (auto ssrc : ssrcs) {
+ // When using ssrc attributes, we are required to at least have a cname.
+ // (See https://tools.ietf.org/html/rfc5576#section-6.1)
+ std::string cnameAttr("cname:");
+ cnameAttr += cname;
+ ssrcAttr->PushEntry(ssrc, cnameAttr);
+ }
+
+ GetAttributeList().SetAttribute(ssrcAttr.release());
+}
+
+void
+SdpMediaSection::AddMsid(const std::string& id, const std::string& appdata)
+{
+ UniquePtr<SdpMsidAttributeList> msids(new SdpMsidAttributeList);
+ if (GetAttributeList().HasAttribute(SdpAttribute::kMsidAttribute)) {
+ msids->mMsids = GetAttributeList().GetMsid().mMsids;
+ }
+ msids->PushEntry(id, appdata);
+ GetAttributeList().SetAttribute(msids.release());
+}
+
+const SdpRidAttributeList::Rid*
+SdpMediaSection::FindRid(const std::string& id) const
+{
+ if (!GetAttributeList().HasAttribute(SdpAttribute::kRidAttribute)) {
+ return nullptr;
+ }
+
+ for (const auto& rid : GetAttributeList().GetRid().mRids) {
+ if (rid.id == id) {
+ return &rid;
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace mozilla
+
diff --git a/media/webrtc/signaling/src/sdp/SdpMediaSection.h b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
new file mode 100644
index 000000000..16242ab16
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
@@ -0,0 +1,361 @@
+/* -*- 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 _SDPMEDIASECTION_H_
+#define _SDPMEDIASECTION_H_
+
+#include "mozilla/Maybe.h"
+#include "signaling/src/sdp/SdpEnum.h"
+#include "signaling/src/sdp/SdpAttributeList.h"
+#include <string>
+#include <vector>
+#include <sstream>
+
+namespace mozilla
+{
+
+class SdpAttributeList;
+
+class SdpConnection;
+
+class SdpMediaSection
+{
+public:
+ enum MediaType { kAudio, kVideo, kText, kApplication, kMessage };
+ // don't add to enum to avoid warnings about unhandled enum values
+ static const size_t kMediaTypes = static_cast<size_t>(kMessage) + 1;
+
+ enum Protocol {
+ kRtpAvp, // RTP/AVP [RFC4566]
+ kUdp, // udp [RFC4566]
+ kVat, // vat [historic]
+ kRtp, // rtp [historic]
+ kUdptl, // udptl [ITU-T]
+ kTcp, // TCP [RFC4145]
+ kRtpAvpf, // RTP/AVPF [RFC4585]
+ kTcpRtpAvp, // TCP/RTP/AVP [RFC4571]
+ kRtpSavp, // RTP/SAVP [RFC3711]
+ kTcpBfcp, // TCP/BFCP [RFC4583]
+ kTcpTlsBfcp, // TCP/TLS/BFCP [RFC4583]
+ kTcpTls, // TCP/TLS [RFC4572]
+ kFluteUdp, // FLUTE/UDP [RFC-mehta-rmt-flute-sdp-05]
+ kTcpMsrp, // TCP/MSRP [RFC4975]
+ kTcpTlsMsrp, // TCP/TLS/MSRP [RFC4975]
+ kDccp, // DCCP [RFC5762]
+ kDccpRtpAvp, // DCCP/RTP/AVP [RFC5762]
+ kDccpRtpSavp, // DCCP/RTP/SAVP [RFC5762]
+ kDccpRtpAvpf, // DCCP/RTP/AVPF [RFC5762]
+ kDccpRtpSavpf, // DCCP/RTP/SAVPF [RFC5762]
+ kRtpSavpf, // RTP/SAVPF [RFC5124]
+ kUdpTlsRtpSavp, // UDP/TLS/RTP/SAVP [RFC5764]
+ kTcpTlsRtpSavp, // TCP/TLS/RTP/SAVP [JSEP-TBD]
+ kDccpTlsRtpSavp, // DCCP/TLS/RTP/SAVP [RFC5764]
+ kUdpTlsRtpSavpf, // UDP/TLS/RTP/SAVPF [RFC5764]
+ kTcpTlsRtpSavpf, // TCP/TLS/RTP/SAVPF [JSEP-TBD]
+ kDccpTlsRtpSavpf, // DCCP/TLS/RTP/SAVPF [RFC5764]
+ kUdpMbmsFecRtpAvp, // UDP/MBMS-FEC/RTP/AVP [RFC6064]
+ kUdpMbmsFecRtpSavp, // UDP/MBMS-FEC/RTP/SAVP [RFC6064]
+ kUdpMbmsRepair, // UDP/MBMS-REPAIR [RFC6064]
+ kFecUdp, // FEC/UDP [RFC6364]
+ kUdpFec, // UDP/FEC [RFC6364]
+ kTcpMrcpv2, // TCP/MRCPv2 [RFC6787]
+ kTcpTlsMrcpv2, // TCP/TLS/MRCPv2 [RFC6787]
+ kPstn, // PSTN [RFC7195]
+ kUdpTlsUdptl, // UDP/TLS/UDPTL [RFC7345]
+ kSctp, // SCTP [draft-ietf-mmusic-sctp-sdp-07]
+ kSctpDtls, // SCTP/DTLS [draft-ietf-mmusic-sctp-sdp-07]
+ kDtlsSctp // DTLS/SCTP [draft-ietf-mmusic-sctp-sdp-07]
+ };
+
+ explicit SdpMediaSection(size_t level) : mLevel(level) {}
+
+ virtual MediaType GetMediaType() const = 0;
+ virtual unsigned int GetPort() const = 0;
+ virtual void SetPort(unsigned int port) = 0;
+ virtual unsigned int GetPortCount() const = 0;
+ virtual Protocol GetProtocol() const = 0;
+ virtual const SdpConnection& GetConnection() const = 0;
+ virtual SdpConnection& GetConnection() = 0;
+ virtual uint32_t GetBandwidth(const std::string& type) const = 0;
+ virtual const std::vector<std::string>& GetFormats() const = 0;
+
+ std::vector<std::string> GetFormatsForSimulcastVersion(
+ size_t simulcastVersion, bool send, bool recv) const;
+ virtual const SdpAttributeList& GetAttributeList() const = 0;
+ virtual SdpAttributeList& GetAttributeList() = 0;
+
+ virtual SdpDirectionAttribute GetDirectionAttribute() const = 0;
+
+ virtual void Serialize(std::ostream&) const = 0;
+
+ virtual void AddCodec(const std::string& pt, const std::string& name,
+ uint32_t clockrate, uint16_t channels) = 0;
+ virtual void ClearCodecs() = 0;
+
+ virtual void AddDataChannel(const std::string& pt, const std::string& name,
+ uint16_t streams) = 0;
+
+ size_t
+ GetLevel() const
+ {
+ return mLevel;
+ }
+
+ inline bool
+ IsReceiving() const
+ {
+ return GetDirectionAttribute().mValue & sdp::kRecv;
+ }
+
+ inline bool
+ IsSending() const
+ {
+ return GetDirectionAttribute().mValue & sdp::kSend;
+ }
+
+ inline void
+ SetReceiving(bool receiving)
+ {
+ auto direction = GetDirectionAttribute().mValue;
+ if (direction & sdp::kSend) {
+ SetDirection(receiving ?
+ SdpDirectionAttribute::kSendrecv :
+ SdpDirectionAttribute::kSendonly);
+ } else {
+ SetDirection(receiving ?
+ SdpDirectionAttribute::kRecvonly :
+ SdpDirectionAttribute::kInactive);
+ }
+ }
+
+ inline void
+ SetSending(bool sending)
+ {
+ auto direction = GetDirectionAttribute().mValue;
+ if (direction & sdp::kRecv) {
+ SetDirection(sending ?
+ SdpDirectionAttribute::kSendrecv :
+ SdpDirectionAttribute::kRecvonly);
+ } else {
+ SetDirection(sending ?
+ SdpDirectionAttribute::kSendonly :
+ SdpDirectionAttribute::kInactive);
+ }
+ }
+
+ inline void SetDirection(SdpDirectionAttribute::Direction direction)
+ {
+ GetAttributeList().SetAttribute(new SdpDirectionAttribute(direction));
+ }
+
+ const SdpFmtpAttributeList::Parameters* FindFmtp(const std::string& pt) const;
+ void SetFmtp(const SdpFmtpAttributeList::Fmtp& fmtp);
+ void RemoveFmtp(const std::string& pt);
+ const SdpRtpmapAttributeList::Rtpmap* FindRtpmap(const std::string& pt) const;
+ const SdpSctpmapAttributeList::Sctpmap* FindSctpmap(
+ const std::string& pt) const;
+ bool HasRtcpFb(const std::string& pt,
+ SdpRtcpFbAttributeList::Type type,
+ const std::string& subType) const;
+ SdpRtcpFbAttributeList GetRtcpFbs() const;
+ void SetRtcpFbs(const SdpRtcpFbAttributeList& rtcpfbs);
+ bool HasFormat(const std::string& format) const
+ {
+ return std::find(GetFormats().begin(), GetFormats().end(), format) !=
+ GetFormats().end();
+ }
+ void SetSsrcs(const std::vector<uint32_t>& ssrcs,
+ const std::string& cname);
+ void AddMsid(const std::string& id, const std::string& appdata);
+ const SdpRidAttributeList::Rid* FindRid(const std::string& id) const;
+
+private:
+ size_t mLevel;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const SdpMediaSection& ms)
+{
+ ms.Serialize(os);
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, SdpMediaSection::MediaType t)
+{
+ switch (t) {
+ case SdpMediaSection::kAudio:
+ return os << "audio";
+ case SdpMediaSection::kVideo:
+ return os << "video";
+ case SdpMediaSection::kText:
+ return os << "text";
+ case SdpMediaSection::kApplication:
+ return os << "application";
+ case SdpMediaSection::kMessage:
+ return os << "message";
+ }
+ MOZ_ASSERT(false, "Unknown MediaType");
+ return os << "?";
+}
+
+inline std::ostream& operator<<(std::ostream& os, SdpMediaSection::Protocol p)
+{
+ switch (p) {
+ case SdpMediaSection::kRtpAvp:
+ return os << "RTP/AVP";
+ case SdpMediaSection::kUdp:
+ return os << "udp";
+ case SdpMediaSection::kVat:
+ return os << "vat";
+ case SdpMediaSection::kRtp:
+ return os << "rtp";
+ case SdpMediaSection::kUdptl:
+ return os << "udptl";
+ case SdpMediaSection::kTcp:
+ return os << "TCP";
+ case SdpMediaSection::kRtpAvpf:
+ return os << "RTP/AVPF";
+ case SdpMediaSection::kTcpRtpAvp:
+ return os << "TCP/RTP/AVP";
+ case SdpMediaSection::kRtpSavp:
+ return os << "RTP/SAVP";
+ case SdpMediaSection::kTcpBfcp:
+ return os << "TCP/BFCP";
+ case SdpMediaSection::kTcpTlsBfcp:
+ return os << "TCP/TLS/BFCP";
+ case SdpMediaSection::kTcpTls:
+ return os << "TCP/TLS";
+ case SdpMediaSection::kFluteUdp:
+ return os << "FLUTE/UDP";
+ case SdpMediaSection::kTcpMsrp:
+ return os << "TCP/MSRP";
+ case SdpMediaSection::kTcpTlsMsrp:
+ return os << "TCP/TLS/MSRP";
+ case SdpMediaSection::kDccp:
+ return os << "DCCP";
+ case SdpMediaSection::kDccpRtpAvp:
+ return os << "DCCP/RTP/AVP";
+ case SdpMediaSection::kDccpRtpSavp:
+ return os << "DCCP/RTP/SAVP";
+ case SdpMediaSection::kDccpRtpAvpf:
+ return os << "DCCP/RTP/AVPF";
+ case SdpMediaSection::kDccpRtpSavpf:
+ return os << "DCCP/RTP/SAVPF";
+ case SdpMediaSection::kRtpSavpf:
+ return os << "RTP/SAVPF";
+ case SdpMediaSection::kUdpTlsRtpSavp:
+ return os << "UDP/TLS/RTP/SAVP";
+ case SdpMediaSection::kTcpTlsRtpSavp:
+ return os << "TCP/TLS/RTP/SAVP";
+ case SdpMediaSection::kDccpTlsRtpSavp:
+ return os << "DCCP/TLS/RTP/SAVP";
+ case SdpMediaSection::kUdpTlsRtpSavpf:
+ return os << "UDP/TLS/RTP/SAVPF";
+ case SdpMediaSection::kTcpTlsRtpSavpf:
+ return os << "TCP/TLS/RTP/SAVPF";
+ case SdpMediaSection::kDccpTlsRtpSavpf:
+ return os << "DCCP/TLS/RTP/SAVPF";
+ case SdpMediaSection::kUdpMbmsFecRtpAvp:
+ return os << "UDP/MBMS-FEC/RTP/AVP";
+ case SdpMediaSection::kUdpMbmsFecRtpSavp:
+ return os << "UDP/MBMS-FEC/RTP/SAVP";
+ case SdpMediaSection::kUdpMbmsRepair:
+ return os << "UDP/MBMS-REPAIR";
+ case SdpMediaSection::kFecUdp:
+ return os << "FEC/UDP";
+ case SdpMediaSection::kUdpFec:
+ return os << "UDP/FEC";
+ case SdpMediaSection::kTcpMrcpv2:
+ return os << "TCP/MRCPv2";
+ case SdpMediaSection::kTcpTlsMrcpv2:
+ return os << "TCP/TLS/MRCPv2";
+ case SdpMediaSection::kPstn:
+ return os << "PSTN";
+ case SdpMediaSection::kUdpTlsUdptl:
+ return os << "UDP/TLS/UDPTL";
+ case SdpMediaSection::kSctp:
+ return os << "SCTP";
+ case SdpMediaSection::kSctpDtls:
+ return os << "SCTP/DTLS";
+ case SdpMediaSection::kDtlsSctp:
+ return os << "DTLS/SCTP";
+ }
+ MOZ_ASSERT(false, "Unknown Protocol");
+ return os << "?";
+}
+
+class SdpConnection
+{
+public:
+ SdpConnection(sdp::AddrType addrType, std::string addr, uint8_t ttl = 0,
+ uint32_t count = 0)
+ : mAddrType(addrType), mAddr(addr), mTtl(ttl), mCount(count)
+ {
+ }
+ ~SdpConnection() {}
+
+ sdp::AddrType
+ GetAddrType() const
+ {
+ return mAddrType;
+ }
+ const std::string&
+ GetAddress() const
+ {
+ return mAddr;
+ }
+ void
+ SetAddress(const std::string& address)
+ {
+ mAddr = address;
+ if (mAddr.find(':') != std::string::npos) {
+ mAddrType = sdp::kIPv6;
+ } else {
+ mAddrType = sdp::kIPv4;
+ }
+ }
+ uint8_t
+ GetTtl() const
+ {
+ return mTtl;
+ }
+ uint32_t
+ GetCount() const
+ {
+ return mCount;
+ }
+
+ void
+ Serialize(std::ostream& os) const
+ {
+ sdp::NetType netType = sdp::kInternet;
+
+ os << "c=" << netType << " " << mAddrType << " " << mAddr;
+
+ if (mTtl) {
+ os << "/" << static_cast<uint32_t>(mTtl);
+ if (mCount) {
+ os << "/" << mCount;
+ }
+ }
+ os << "\r\n";
+ }
+
+private:
+ sdp::AddrType mAddrType;
+ std::string mAddr;
+ uint8_t mTtl; // 0-255; 0 when unset
+ uint32_t mCount; // 0 when unset
+};
+
+inline std::ostream& operator<<(std::ostream& os, const SdpConnection& c)
+{
+ c.Serialize(os);
+ return os;
+}
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SipccSdp.cpp b/media/webrtc/signaling/src/sdp/SipccSdp.cpp
new file mode 100644
index 000000000..c23fcf7e9
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdp.cpp
@@ -0,0 +1,180 @@
+/* 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/. */
+
+#include "signaling/src/sdp/SipccSdp.h"
+
+#include <cstdlib>
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Assertions.h"
+#include "signaling/src/sdp/SdpErrorHolder.h"
+
+#ifdef CRLF
+#undef CRLF
+#endif
+#define CRLF "\r\n"
+
+namespace mozilla
+{
+
+const SdpOrigin&
+SipccSdp::GetOrigin() const
+{
+ return mOrigin;
+}
+
+uint32_t
+SipccSdp::GetBandwidth(const std::string& type) const
+{
+ auto found = mBandwidths.find(type);
+ if (found == mBandwidths.end()) {
+ return 0;
+ }
+ return found->second;
+}
+
+const SdpMediaSection&
+SipccSdp::GetMediaSection(size_t level) const
+{
+ if (level > mMediaSections.values.size()) {
+ MOZ_CRASH();
+ }
+ return *mMediaSections.values[level];
+}
+
+SdpMediaSection&
+SipccSdp::GetMediaSection(size_t level)
+{
+ if (level > mMediaSections.values.size()) {
+ MOZ_CRASH();
+ }
+ return *mMediaSections.values[level];
+}
+
+SdpMediaSection&
+SipccSdp::AddMediaSection(SdpMediaSection::MediaType mediaType,
+ SdpDirectionAttribute::Direction dir, uint16_t port,
+ SdpMediaSection::Protocol protocol,
+ sdp::AddrType addrType, const std::string& addr)
+{
+ size_t level = mMediaSections.values.size();
+ SipccSdpMediaSection* media =
+ new SipccSdpMediaSection(level, &mAttributeList);
+ media->mMediaType = mediaType;
+ media->mPort = port;
+ media->mPortCount = 0;
+ media->mProtocol = protocol;
+ media->mConnection = MakeUnique<SdpConnection>(addrType, addr);
+ media->GetAttributeList().SetAttribute(new SdpDirectionAttribute(dir));
+ mMediaSections.values.push_back(media);
+ return *media;
+}
+
+bool
+SipccSdp::LoadOrigin(sdp_t* sdp, SdpErrorHolder& errorHolder)
+{
+ std::string username = sdp_get_owner_username(sdp);
+ uint64_t sessId = strtoull(sdp_get_owner_sessionid(sdp), nullptr, 10);
+ uint64_t sessVer = strtoull(sdp_get_owner_version(sdp), nullptr, 10);
+
+ sdp_nettype_e type = sdp_get_owner_network_type(sdp);
+ if (type != SDP_NT_INTERNET) {
+ errorHolder.AddParseError(2, "Unsupported network type");
+ return false;
+ }
+
+ sdp::AddrType addrType;
+ switch (sdp_get_owner_address_type(sdp)) {
+ case SDP_AT_IP4:
+ addrType = sdp::kIPv4;
+ break;
+ case SDP_AT_IP6:
+ addrType = sdp::kIPv6;
+ break;
+ default:
+ errorHolder.AddParseError(2, "Unsupported address type");
+ return false;
+ }
+
+ std::string address = sdp_get_owner_address(sdp);
+ mOrigin = SdpOrigin(username, sessId, sessVer, addrType, address);
+ return true;
+}
+
+bool
+SipccSdp::Load(sdp_t* sdp, SdpErrorHolder& errorHolder)
+{
+ // Believe it or not, SDP_SESSION_LEVEL is 0xFFFF
+ if (!mAttributeList.Load(sdp, SDP_SESSION_LEVEL, errorHolder)) {
+ return false;
+ }
+
+ if (!LoadOrigin(sdp, errorHolder)) {
+ return false;
+ }
+
+ if (!mBandwidths.Load(sdp, SDP_SESSION_LEVEL, errorHolder)) {
+ return false;
+ }
+
+ for (int i = 0; i < sdp_get_num_media_lines(sdp); ++i) {
+ // note that we pass a "level" here that is one higher
+ // sipcc counts media sections from 1, using 0xFFFF as the "session"
+ UniquePtr<SipccSdpMediaSection> section(
+ new SipccSdpMediaSection(i, &mAttributeList));
+ if (!section->Load(sdp, i + 1, errorHolder)) {
+ return false;
+ }
+ mMediaSections.values.push_back(section.release());
+ }
+ return true;
+}
+
+void
+SipccSdp::Serialize(std::ostream& os) const
+{
+ os << "v=0" << CRLF << mOrigin << "s=-" << CRLF;
+
+ // We don't support creating i=, u=, e=, p=
+ // We don't generate c= at the session level (only in media)
+
+ mBandwidths.Serialize(os);
+ os << "t=0 0" << CRLF;
+
+ // We don't support r= or z=
+
+ // attributes
+ os << mAttributeList;
+
+ // media sections
+ for (const SdpMediaSection* msection : mMediaSections.values) {
+ os << *msection;
+ }
+}
+
+bool
+SipccSdpBandwidths::Load(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ size_t count = sdp_get_num_bw_lines(sdp, level);
+ for (size_t i = 1; i <= count; ++i) {
+ sdp_bw_modifier_e bwtype = sdp_get_bw_modifier(sdp, level, i);
+ uint32_t bandwidth = sdp_get_bw_value(sdp, level, i);
+ if (bwtype != SDP_BW_MODIFIER_UNSUPPORTED) {
+ const char* typeName = sdp_get_bw_modifier_name(bwtype);
+ (*this)[typeName] = bandwidth;
+ }
+ }
+
+ return true;
+}
+
+void
+SipccSdpBandwidths::Serialize(std::ostream& os) const
+{
+ for (auto i = begin(); i != end(); ++i) {
+ os << "b=" << i->first << ":" << i->second << CRLF;
+ }
+}
+
+} // namespace mozilla
diff --git a/media/webrtc/signaling/src/sdp/SipccSdp.h b/media/webrtc/signaling/src/sdp/SipccSdp.h
new file mode 100644
index 000000000..04ef202ab
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdp.h
@@ -0,0 +1,88 @@
+/* -*- 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 _SIPCCSDP_H_
+#define _SIPCCSDP_H_
+
+#include <map>
+#include <vector>
+#include "mozilla/Attributes.h"
+
+#include "signaling/src/sdp/Sdp.h"
+#include "signaling/src/sdp/SipccSdpMediaSection.h"
+#include "signaling/src/sdp/SipccSdpAttributeList.h"
+extern "C" {
+#include "signaling/src/sdp/sipcc/sdp.h"
+}
+
+#include "signaling/src/common/PtrVector.h"
+
+namespace mozilla
+{
+
+class SipccSdpParser;
+class SdpErrorHolder;
+
+class SipccSdp final : public Sdp
+{
+ friend class SipccSdpParser;
+
+public:
+ explicit SipccSdp(const SdpOrigin& origin)
+ : mOrigin(origin), mAttributeList(nullptr)
+ {
+ }
+
+ virtual const SdpOrigin& GetOrigin() const override;
+
+ // Note: connection information is always retrieved from media sections
+ virtual uint32_t GetBandwidth(const std::string& type) const override;
+
+ virtual size_t
+ GetMediaSectionCount() const override
+ {
+ return mMediaSections.values.size();
+ }
+
+ virtual const SdpAttributeList&
+ GetAttributeList() const override
+ {
+ return mAttributeList;
+ }
+
+ virtual SdpAttributeList&
+ GetAttributeList() override
+ {
+ return mAttributeList;
+ }
+
+ virtual const SdpMediaSection& GetMediaSection(size_t level) const
+ override;
+
+ virtual SdpMediaSection& GetMediaSection(size_t level) override;
+
+ virtual SdpMediaSection& AddMediaSection(
+ SdpMediaSection::MediaType media, SdpDirectionAttribute::Direction dir,
+ uint16_t port, SdpMediaSection::Protocol proto, sdp::AddrType addrType,
+ const std::string& addr) override;
+
+ virtual void Serialize(std::ostream&) const override;
+
+private:
+ SipccSdp() : mOrigin("", 0, 0, sdp::kIPv4, ""), mAttributeList(nullptr) {}
+
+ bool Load(sdp_t* sdp, SdpErrorHolder& errorHolder);
+ bool LoadOrigin(sdp_t* sdp, SdpErrorHolder& errorHolder);
+
+ SdpOrigin mOrigin;
+ SipccSdpBandwidths mBandwidths;
+ SipccSdpAttributeList mAttributeList;
+ PtrVector<SipccSdpMediaSection> mMediaSections;
+};
+
+} // namespace mozilla
+
+#endif // _sdp_h_
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
new file mode 100644
index 000000000..5357f4728
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.cpp
@@ -0,0 +1,1413 @@
+/* -*- 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/. */
+
+#include "signaling/src/sdp/SipccSdpAttributeList.h"
+
+#include <ostream>
+#include "mozilla/Assertions.h"
+#include "signaling/src/sdp/SdpErrorHolder.h"
+
+extern "C" {
+#include "signaling/src/sdp/sipcc/sdp_private.h"
+}
+
+namespace mozilla
+{
+
+/* static */ const std::string SipccSdpAttributeList::kEmptyString = "";
+
+SipccSdpAttributeList::SipccSdpAttributeList(
+ const SipccSdpAttributeList* sessionLevel)
+ : mSessionLevel(sessionLevel)
+{
+ memset(&mAttributes, 0, sizeof(mAttributes));
+}
+
+SipccSdpAttributeList::~SipccSdpAttributeList()
+{
+ for (size_t i = 0; i < kNumAttributeTypes; ++i) {
+ delete mAttributes[i];
+ }
+}
+
+bool
+SipccSdpAttributeList::HasAttribute(AttributeType type,
+ bool sessionFallback) const
+{
+ return !!GetAttribute(type, sessionFallback);
+}
+
+const SdpAttribute*
+SipccSdpAttributeList::GetAttribute(AttributeType type,
+ bool sessionFallback) const
+{
+ const SdpAttribute* value = mAttributes[static_cast<size_t>(type)];
+ // Only do fallback when the attribute can appear at both the media and
+ // session level
+ if (!value && !AtSessionLevel() && sessionFallback &&
+ SdpAttribute::IsAllowedAtSessionLevel(type) &&
+ SdpAttribute::IsAllowedAtMediaLevel(type)) {
+ return mSessionLevel->GetAttribute(type, false);
+ }
+ return value;
+}
+
+void
+SipccSdpAttributeList::RemoveAttribute(AttributeType type)
+{
+ delete mAttributes[static_cast<size_t>(type)];
+ mAttributes[static_cast<size_t>(type)] = nullptr;
+}
+
+void
+SipccSdpAttributeList::Clear()
+{
+ for (size_t i = 0; i < kNumAttributeTypes; ++i) {
+ RemoveAttribute(static_cast<AttributeType>(i));
+ }
+}
+
+void
+SipccSdpAttributeList::SetAttribute(SdpAttribute* attr)
+{
+ if (!IsAllowedHere(attr->GetType())) {
+ MOZ_ASSERT(false, "This type of attribute is not allowed here");
+ return;
+ }
+ RemoveAttribute(attr->GetType());
+ mAttributes[attr->GetType()] = attr;
+}
+
+void
+SipccSdpAttributeList::LoadSimpleString(sdp_t* sdp, uint16_t level,
+ sdp_attr_e attr,
+ AttributeType targetType,
+ SdpErrorHolder& errorHolder)
+{
+ const char* value = sdp_attr_get_simple_string(sdp, attr, level, 0, 1);
+ if (value) {
+ if (!IsAllowedHere(targetType)) {
+ uint32_t lineNumber = sdp_attr_line_number(sdp, attr, level, 0, 1);
+ WarnAboutMisplacedAttribute(targetType, lineNumber, errorHolder);
+ } else {
+ SetAttribute(new SdpStringAttribute(targetType, std::string(value)));
+ }
+ }
+}
+
+void
+SipccSdpAttributeList::LoadSimpleStrings(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ LoadSimpleString(sdp, level, SDP_ATTR_MID, SdpAttribute::kMidAttribute,
+ errorHolder);
+ LoadSimpleString(sdp, level, SDP_ATTR_LABEL, SdpAttribute::kLabelAttribute,
+ errorHolder);
+}
+
+void
+SipccSdpAttributeList::LoadSimpleNumber(sdp_t* sdp, uint16_t level,
+ sdp_attr_e attr,
+ AttributeType targetType,
+ SdpErrorHolder& errorHolder)
+{
+ if (sdp_attr_valid(sdp, attr, level, 0, 1)) {
+ if (!IsAllowedHere(targetType)) {
+ uint32_t lineNumber = sdp_attr_line_number(sdp, attr, level, 0, 1);
+ WarnAboutMisplacedAttribute(targetType, lineNumber, errorHolder);
+ } else {
+ uint32_t value = sdp_attr_get_simple_u32(sdp, attr, level, 0, 1);
+ SetAttribute(new SdpNumberAttribute(targetType, value));
+ }
+ }
+}
+
+void
+SipccSdpAttributeList::LoadSimpleNumbers(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ LoadSimpleNumber(sdp, level, SDP_ATTR_PTIME, SdpAttribute::kPtimeAttribute,
+ errorHolder);
+ LoadSimpleNumber(sdp, level, SDP_ATTR_MAXPTIME,
+ SdpAttribute::kMaxptimeAttribute, errorHolder);
+}
+
+void
+SipccSdpAttributeList::LoadFlags(sdp_t* sdp, uint16_t level)
+{
+ if (AtSessionLevel()) {
+ if (sdp_attr_valid(sdp, SDP_ATTR_ICE_LITE, level, 0, 1)) {
+ SetAttribute(new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute));
+ }
+ } else { // media-level
+ if (sdp_attr_valid(sdp, SDP_ATTR_RTCP_MUX, level, 0, 1)) {
+ SetAttribute(new SdpFlagAttribute(SdpAttribute::kRtcpMuxAttribute));
+ }
+ if (sdp_attr_valid(sdp, SDP_ATTR_END_OF_CANDIDATES, level, 0, 1)) {
+ SetAttribute(
+ new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
+ }
+ if (sdp_attr_valid(sdp, SDP_ATTR_BUNDLE_ONLY, level, 0, 1)) {
+ SetAttribute(new SdpFlagAttribute(SdpAttribute::kBundleOnlyAttribute));
+ }
+ }
+}
+
+static void
+ConvertDirection(sdp_direction_e sipcc_direction,
+ SdpDirectionAttribute::Direction* dir_outparam)
+{
+ switch (sipcc_direction) {
+ case SDP_DIRECTION_SENDRECV:
+ *dir_outparam = SdpDirectionAttribute::kSendrecv;
+ return;
+ case SDP_DIRECTION_SENDONLY:
+ *dir_outparam = SdpDirectionAttribute::kSendonly;
+ return;
+ case SDP_DIRECTION_RECVONLY:
+ *dir_outparam = SdpDirectionAttribute::kRecvonly;
+ return;
+ case SDP_DIRECTION_INACTIVE:
+ *dir_outparam = SdpDirectionAttribute::kInactive;
+ return;
+ case SDP_MAX_QOS_DIRECTIONS:
+ // Nothing actually sets this value.
+ // Fall through to MOZ_CRASH below.
+ {
+ }
+ }
+
+ MOZ_CRASH("Invalid direction from sipcc; this is probably corruption");
+}
+
+void
+SipccSdpAttributeList::LoadDirection(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ SdpDirectionAttribute::Direction dir;
+ ConvertDirection(sdp_get_media_direction(sdp, level, 0), &dir);
+ SetAttribute(new SdpDirectionAttribute(dir));
+}
+
+void
+SipccSdpAttributeList::LoadIceAttributes(sdp_t* sdp, uint16_t level)
+{
+ char* value;
+ sdp_result_e sdpres =
+ sdp_attr_get_ice_attribute(sdp, level, 0, SDP_ATTR_ICE_UFRAG, 1, &value);
+ if (sdpres == SDP_SUCCESS) {
+ SetAttribute(new SdpStringAttribute(SdpAttribute::kIceUfragAttribute,
+ std::string(value)));
+ }
+ sdpres =
+ sdp_attr_get_ice_attribute(sdp, level, 0, SDP_ATTR_ICE_PWD, 1, &value);
+ if (sdpres == SDP_SUCCESS) {
+ SetAttribute(new SdpStringAttribute(SdpAttribute::kIcePwdAttribute,
+ std::string(value)));
+ }
+
+ const char* iceOptVal =
+ sdp_attr_get_simple_string(sdp, SDP_ATTR_ICE_OPTIONS, level, 0, 1);
+ if (iceOptVal) {
+ auto* iceOptions =
+ new SdpOptionsAttribute(SdpAttribute::kIceOptionsAttribute);
+ iceOptions->Load(iceOptVal);
+ SetAttribute(iceOptions);
+ }
+}
+
+bool
+SipccSdpAttributeList::LoadFingerprint(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ char* value;
+ UniquePtr<SdpFingerprintAttributeList> fingerprintAttrs;
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_result_e result = sdp_attr_get_dtls_fingerprint_attribute(
+ sdp, level, 0, SDP_ATTR_DTLS_FINGERPRINT, i, &value);
+
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+
+ std::string fingerprintAttr(value);
+ uint32_t lineNumber =
+ sdp_attr_line_number(sdp, SDP_ATTR_DTLS_FINGERPRINT, level, 0, i);
+
+ // sipcc does not expose parse code for this
+ size_t start = fingerprintAttr.find_first_not_of(" \t");
+ if (start == std::string::npos) {
+ errorHolder.AddParseError(lineNumber, "Empty fingerprint attribute");
+ return false;
+ }
+
+ size_t end = fingerprintAttr.find_first_of(" \t", start);
+ if (end == std::string::npos) {
+ // One token, no trailing ws
+ errorHolder.AddParseError(lineNumber,
+ "Only one token in fingerprint attribute");
+ return false;
+ }
+
+ std::string algorithmToken(fingerprintAttr.substr(start, end - start));
+
+ start = fingerprintAttr.find_first_not_of(" \t", end);
+ if (start == std::string::npos) {
+ // One token, trailing ws
+ errorHolder.AddParseError(lineNumber,
+ "Only one token in fingerprint attribute");
+ return false;
+ }
+
+ std::string fingerprintToken(fingerprintAttr.substr(start));
+
+ std::vector<uint8_t> fingerprint =
+ SdpFingerprintAttributeList::ParseFingerprint(fingerprintToken);
+ if (fingerprint.size() == 0) {
+ errorHolder.AddParseError(lineNumber, "Malformed fingerprint token");
+ return false;
+ }
+
+ if (!fingerprintAttrs) {
+ fingerprintAttrs.reset(new SdpFingerprintAttributeList);
+ }
+
+ // Don't assert on unknown algorithm, just skip
+ fingerprintAttrs->PushEntry(algorithmToken, fingerprint, false);
+ }
+
+ if (fingerprintAttrs) {
+ SetAttribute(fingerprintAttrs.release());
+ }
+
+ return true;
+}
+
+void
+SipccSdpAttributeList::LoadCandidate(sdp_t* sdp, uint16_t level)
+{
+ char* value;
+ auto candidates =
+ MakeUnique<SdpMultiStringAttribute>(SdpAttribute::kCandidateAttribute);
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_result_e result = sdp_attr_get_ice_attribute(
+ sdp, level, 0, SDP_ATTR_ICE_CANDIDATE, i, &value);
+
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+
+ candidates->mValues.push_back(value);
+ }
+
+ if (!candidates->mValues.empty()) {
+ SetAttribute(candidates.release());
+ }
+}
+
+bool
+SipccSdpAttributeList::LoadSctpmap(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ auto sctpmap = MakeUnique<SdpSctpmapAttributeList>();
+ for (uint16_t i = 0; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SCTPMAP, i + 1);
+
+ if (!attr) {
+ break;
+ }
+
+ // Yeah, this is a little weird, but for now we'll just store this as a
+ // payload type.
+ uint16_t payloadType = attr->attr.sctpmap.port;
+ uint16_t streams = attr->attr.sctpmap.streams;
+ const char* name = attr->attr.sctpmap.protocol;
+
+ std::ostringstream osPayloadType;
+ osPayloadType << payloadType;
+ sctpmap->PushEntry(osPayloadType.str(), name, streams);
+ }
+
+ if (!sctpmap->mSctpmaps.empty()) {
+ SetAttribute(sctpmap.release());
+ }
+
+ return true;
+}
+
+SdpRtpmapAttributeList::CodecType
+SipccSdpAttributeList::GetCodecType(rtp_ptype type)
+{
+ switch (type) {
+ case RTP_PCMU:
+ return SdpRtpmapAttributeList::kPCMU;
+ case RTP_PCMA:
+ return SdpRtpmapAttributeList::kPCMA;
+ case RTP_G722:
+ return SdpRtpmapAttributeList::kG722;
+ case RTP_H264_P0:
+ case RTP_H264_P1:
+ return SdpRtpmapAttributeList::kH264;
+ case RTP_OPUS:
+ return SdpRtpmapAttributeList::kOpus;
+ case RTP_VP8:
+ return SdpRtpmapAttributeList::kVP8;
+ case RTP_VP9:
+ return SdpRtpmapAttributeList::kVP9;
+ case RTP_RED:
+ return SdpRtpmapAttributeList::kRed;
+ case RTP_ULPFEC:
+ return SdpRtpmapAttributeList::kUlpfec;
+ case RTP_TELEPHONE_EVENT:
+ return SdpRtpmapAttributeList::kTelephoneEvent;
+ case RTP_NONE:
+ // Happens when sipcc doesn't know how to translate to the enum
+ case RTP_CELP:
+ case RTP_G726:
+ case RTP_GSM:
+ case RTP_G723:
+ case RTP_DVI4:
+ case RTP_DVI4_II:
+ case RTP_LPC:
+ case RTP_G728:
+ case RTP_G729:
+ case RTP_JPEG:
+ case RTP_NV:
+ case RTP_H261:
+ case RTP_L16:
+ case RTP_H263:
+ case RTP_ILBC:
+ case RTP_I420:
+ return SdpRtpmapAttributeList::kOtherCodec;
+ }
+ MOZ_CRASH("Invalid codec type from sipcc. Probably corruption.");
+}
+
+bool
+SipccSdpAttributeList::LoadRtpmap(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ auto rtpmap = MakeUnique<SdpRtpmapAttributeList>();
+ uint16_t count;
+ sdp_result_e result =
+ sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_RTPMAP, &count);
+ if (result != SDP_SUCCESS) {
+ MOZ_ASSERT(false, "Unable to get rtpmap size");
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unable to get rtpmap size");
+ return false;
+ }
+ for (uint16_t i = 0; i < count; ++i) {
+ uint16_t pt = sdp_attr_get_rtpmap_payload_type(sdp, level, 0, i + 1);
+ const char* ccName = sdp_attr_get_rtpmap_encname(sdp, level, 0, i + 1);
+
+ if (!ccName) {
+ // Probably no rtpmap attribute for a pt in an m-line
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "No rtpmap attribute for payload type");
+ continue;
+ }
+
+ std::string name(ccName);
+
+ SdpRtpmapAttributeList::CodecType codec =
+ GetCodecType(sdp_get_known_payload_type(sdp, level, pt));
+
+ uint32_t clock = sdp_attr_get_rtpmap_clockrate(sdp, level, 0, i + 1);
+ uint16_t channels = 0;
+
+ // sipcc gives us a channels value of "1" for video
+ if (sdp_get_media_type(sdp, level) == SDP_MEDIA_AUDIO) {
+ channels = sdp_attr_get_rtpmap_num_chan(sdp, level, 0, i + 1);
+ }
+
+ std::ostringstream osPayloadType;
+ osPayloadType << pt;
+ rtpmap->PushEntry(osPayloadType.str(), codec, name, clock, channels);
+ }
+
+ if (!rtpmap->mRtpmaps.empty()) {
+ SetAttribute(rtpmap.release());
+ }
+
+ return true;
+}
+
+void
+SipccSdpAttributeList::LoadSetup(sdp_t* sdp, uint16_t level)
+{
+ sdp_setup_type_e setupType;
+ auto sdpres = sdp_attr_get_setup_attribute(sdp, level, 0, 1, &setupType);
+
+ if (sdpres != SDP_SUCCESS) {
+ return;
+ }
+
+ switch (setupType) {
+ case SDP_SETUP_ACTIVE:
+ SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kActive));
+ return;
+ case SDP_SETUP_PASSIVE:
+ SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kPassive));
+ return;
+ case SDP_SETUP_ACTPASS:
+ SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kActpass));
+ return;
+ case SDP_SETUP_HOLDCONN:
+ SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kHoldconn));
+ return;
+ case SDP_SETUP_UNKNOWN:
+ return;
+ case SDP_SETUP_NOT_FOUND:
+ case SDP_MAX_SETUP:
+ // There is no code that will set these.
+ // Fall through to MOZ_CRASH() below.
+ {
+ }
+ }
+
+ MOZ_CRASH("Invalid setup type from sipcc. This is probably corruption.");
+}
+
+void
+SipccSdpAttributeList::LoadSsrc(sdp_t* sdp, uint16_t level)
+{
+ auto ssrcs = MakeUnique<SdpSsrcAttributeList>();
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SSRC, i);
+
+ if (!attr) {
+ break;
+ }
+
+ sdp_ssrc_t* ssrc = &(attr->attr.ssrc);
+ ssrcs->PushEntry(ssrc->ssrc, ssrc->attribute);
+ }
+
+ if (!ssrcs->mSsrcs.empty()) {
+ SetAttribute(ssrcs.release());
+ }
+}
+
+bool
+SipccSdpAttributeList::LoadImageattr(sdp_t* sdp,
+ uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ UniquePtr<SdpImageattrAttributeList> imageattrs(
+ new SdpImageattrAttributeList);
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ const char* imageattrRaw = sdp_attr_get_simple_string(sdp,
+ SDP_ATTR_IMAGEATTR,
+ level,
+ 0,
+ i);
+ if (!imageattrRaw) {
+ break;
+ }
+
+ std::string error;
+ size_t errorPos;
+ if (!imageattrs->PushEntry(imageattrRaw, &error, &errorPos)) {
+ std::ostringstream fullError;
+ fullError << error << " at column " << errorPos;
+ errorHolder.AddParseError(
+ sdp_attr_line_number(sdp, SDP_ATTR_IMAGEATTR, level, 0, i),
+ fullError.str());
+ return false;
+ }
+ }
+
+ if (!imageattrs->mImageattrs.empty()) {
+ SetAttribute(imageattrs.release());
+ }
+ return true;
+}
+
+bool
+SipccSdpAttributeList::LoadSimulcast(sdp_t* sdp,
+ uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ const char* simulcastRaw = sdp_attr_get_simple_string(sdp,
+ SDP_ATTR_SIMULCAST,
+ level,
+ 0,
+ 1);
+ if (!simulcastRaw) {
+ return true;
+ }
+
+ UniquePtr<SdpSimulcastAttribute> simulcast(
+ new SdpSimulcastAttribute);
+
+ std::istringstream is(simulcastRaw);
+ std::string error;
+ if (!simulcast->Parse(is, &error)) {
+ std::ostringstream fullError;
+ fullError << error << " at column " << is.tellg();
+ errorHolder.AddParseError(
+ sdp_attr_line_number(sdp, SDP_ATTR_SIMULCAST, level, 0, 1),
+ fullError.str());
+ return false;
+ }
+
+ SetAttribute(simulcast.release());
+ return true;
+}
+
+bool
+SipccSdpAttributeList::LoadGroups(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ uint16_t attrCount = 0;
+ if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_GROUP, &attrCount) !=
+ SDP_SUCCESS) {
+ MOZ_ASSERT(false, "Could not get count of group attributes");
+ errorHolder.AddParseError(0, "Could not get count of group attributes");
+ return false;
+ }
+
+ UniquePtr<SdpGroupAttributeList> groups = MakeUnique<SdpGroupAttributeList>();
+ for (uint16_t attr = 1; attr <= attrCount; ++attr) {
+ SdpGroupAttributeList::Semantics semantics;
+ std::vector<std::string> tags;
+
+ switch (sdp_get_group_attr(sdp, level, 0, attr)) {
+ case SDP_GROUP_ATTR_FID:
+ semantics = SdpGroupAttributeList::kFid;
+ break;
+ case SDP_GROUP_ATTR_LS:
+ semantics = SdpGroupAttributeList::kLs;
+ break;
+ case SDP_GROUP_ATTR_ANAT:
+ semantics = SdpGroupAttributeList::kAnat;
+ break;
+ case SDP_GROUP_ATTR_BUNDLE:
+ semantics = SdpGroupAttributeList::kBundle;
+ break;
+ default:
+ continue;
+ }
+
+ uint16_t idCount = sdp_get_group_num_id(sdp, level, 0, attr);
+ for (uint16_t id = 1; id <= idCount; ++id) {
+ const char* idStr = sdp_get_group_id(sdp, level, 0, attr, id);
+ if (!idStr) {
+ std::ostringstream os;
+ os << "bad a=group identifier at " << (attr - 1) << ", " << (id - 1);
+ errorHolder.AddParseError(0, os.str());
+ return false;
+ }
+ tags.push_back(std::string(idStr));
+ }
+ groups->PushEntry(semantics, tags);
+ }
+
+ if (!groups->mGroups.empty()) {
+ SetAttribute(groups.release());
+ }
+
+ return true;
+}
+
+bool
+SipccSdpAttributeList::LoadMsidSemantics(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ auto msidSemantics = MakeUnique<SdpMsidSemanticAttributeList>();
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_MSID_SEMANTIC, i);
+
+ if (!attr) {
+ break;
+ }
+
+ sdp_msid_semantic_t* msid_semantic = &(attr->attr.msid_semantic);
+ std::vector<std::string> msids;
+ for (size_t i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
+ if (!msid_semantic->msids[i]) {
+ break;
+ }
+
+ msids.push_back(msid_semantic->msids[i]);
+ }
+
+ msidSemantics->PushEntry(msid_semantic->semantic, msids);
+ }
+
+ if (!msidSemantics->mMsidSemantics.empty()) {
+ SetAttribute(msidSemantics.release());
+ }
+ return true;
+}
+
+void
+SipccSdpAttributeList::LoadIdentity(sdp_t* sdp, uint16_t level)
+{
+ const char* val = sdp_attr_get_long_string(sdp, SDP_ATTR_IDENTITY, level, 0, 1);
+ if (val) {
+ SetAttribute(new SdpStringAttribute(SdpAttribute::kIdentityAttribute,
+ std::string(val)));
+ }
+}
+
+void
+SipccSdpAttributeList::LoadDtlsMessage(sdp_t* sdp, uint16_t level)
+{
+ const char* val = sdp_attr_get_long_string(sdp, SDP_ATTR_DTLS_MESSAGE, level,
+ 0, 1);
+ if (val) {
+ // sipcc does not expose parse code for this, so we use a SDParta-provided
+ // parser
+ std::string strval(val);
+ SetAttribute(new SdpDtlsMessageAttribute(strval));
+ }
+}
+
+void
+SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level)
+{
+ auto fmtps = MakeUnique<SdpFmtpAttributeList>();
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i);
+
+ if (!attr) {
+ break;
+ }
+
+ sdp_fmtp_t* fmtp = &(attr->attr.fmtp);
+
+ // Get the payload type
+ std::stringstream osPayloadType;
+ // payload_num is the number in the fmtp attribute, verbatim
+ osPayloadType << fmtp->payload_num;
+
+ // Get parsed form of parameters, if supported
+ UniquePtr<SdpFmtpAttributeList::Parameters> parameters;
+
+ rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num);
+
+ switch (codec) {
+ case RTP_H264_P0:
+ case RTP_H264_P1: {
+ SdpFmtpAttributeList::H264Parameters* h264Parameters(
+ new SdpFmtpAttributeList::H264Parameters);
+
+ sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets,
+ sizeof(h264Parameters->sprop_parameter_sets));
+
+ h264Parameters->level_asymmetry_allowed =
+ !!(fmtp->level_asymmetry_allowed);
+
+ h264Parameters->packetization_mode = fmtp->packetization_mode;
+ sscanf(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id);
+ h264Parameters->max_mbps = fmtp->max_mbps;
+ h264Parameters->max_fs = fmtp->max_fs;
+ h264Parameters->max_cpb = fmtp->max_cpb;
+ h264Parameters->max_dpb = fmtp->max_dpb;
+ h264Parameters->max_br = fmtp->max_br;
+
+ parameters.reset(h264Parameters);
+ } break;
+ case RTP_VP9: {
+ SdpFmtpAttributeList::VP8Parameters* vp9Parameters(
+ new SdpFmtpAttributeList::VP8Parameters(
+ SdpRtpmapAttributeList::kVP9));
+
+ vp9Parameters->max_fs = fmtp->max_fs;
+ vp9Parameters->max_fr = fmtp->max_fr;
+
+ parameters.reset(vp9Parameters);
+ } break;
+ case RTP_VP8: {
+ SdpFmtpAttributeList::VP8Parameters* vp8Parameters(
+ new SdpFmtpAttributeList::VP8Parameters(
+ SdpRtpmapAttributeList::kVP8));
+
+ vp8Parameters->max_fs = fmtp->max_fs;
+ vp8Parameters->max_fr = fmtp->max_fr;
+
+ parameters.reset(vp8Parameters);
+ } break;
+ case RTP_RED: {
+ SdpFmtpAttributeList::RedParameters* redParameters(
+ new SdpFmtpAttributeList::RedParameters);
+ for (int i = 0;
+ i < SDP_FMTP_MAX_REDUNDANT_ENCODINGS && fmtp->redundant_encodings[i];
+ ++i) {
+ redParameters->encodings.push_back(fmtp->redundant_encodings[i]);
+ }
+
+ parameters.reset(redParameters);
+ } break;
+ case RTP_OPUS: {
+ SdpFmtpAttributeList::OpusParameters* opusParameters(
+ new SdpFmtpAttributeList::OpusParameters);
+ opusParameters->maxplaybackrate = fmtp->maxplaybackrate;
+ opusParameters->stereo = fmtp->stereo;
+ opusParameters->useInBandFec = fmtp->useinbandfec;
+ parameters.reset(opusParameters);
+ } break;
+ case RTP_TELEPHONE_EVENT: {
+ SdpFmtpAttributeList::TelephoneEventParameters* teParameters(
+ new SdpFmtpAttributeList::TelephoneEventParameters);
+ if (strlen(fmtp->dtmf_tones) > 0) {
+ teParameters->dtmfTones = fmtp->dtmf_tones;
+ }
+ parameters.reset(teParameters);
+ } break;
+ default: {
+ }
+ }
+
+ fmtps->PushEntry(osPayloadType.str(), Move(parameters));
+ }
+
+ if (!fmtps->mFmtps.empty()) {
+ SetAttribute(fmtps.release());
+ }
+}
+
+void
+SipccSdpAttributeList::LoadMsids(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ uint16_t attrCount = 0;
+ if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_MSID, &attrCount) !=
+ SDP_SUCCESS) {
+ MOZ_ASSERT(false, "Unable to get count of msid attributes");
+ errorHolder.AddParseError(0, "Unable to get count of msid attributes");
+ return;
+ }
+ auto msids = MakeUnique<SdpMsidAttributeList>();
+ for (uint16_t i = 1; i <= attrCount; ++i) {
+ uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_MSID, level, 0, i);
+
+ const char* identifier = sdp_attr_get_msid_identifier(sdp, level, 0, i);
+ if (!identifier) {
+ errorHolder.AddParseError(lineNumber, "msid attribute with bad identity");
+ continue;
+ }
+
+ const char* appdata = sdp_attr_get_msid_appdata(sdp, level, 0, i);
+ if (!appdata) {
+ errorHolder.AddParseError(lineNumber, "msid attribute with bad appdata");
+ continue;
+ }
+
+ msids->PushEntry(identifier, appdata);
+ }
+
+ if (!msids->mMsids.empty()) {
+ SetAttribute(msids.release());
+ }
+}
+
+bool
+SipccSdpAttributeList::LoadRid(sdp_t* sdp,
+ uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ UniquePtr<SdpRidAttributeList> rids(new SdpRidAttributeList);
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ const char* ridRaw = sdp_attr_get_simple_string(sdp,
+ SDP_ATTR_RID,
+ level,
+ 0,
+ i);
+ if (!ridRaw) {
+ break;
+ }
+
+ std::string error;
+ size_t errorPos;
+ if (!rids->PushEntry(ridRaw, &error, &errorPos)) {
+ std::ostringstream fullError;
+ fullError << error << " at column " << errorPos;
+ errorHolder.AddParseError(
+ sdp_attr_line_number(sdp, SDP_ATTR_RID, level, 0, i),
+ fullError.str());
+ return false;
+ }
+ }
+
+ if (!rids->mRids.empty()) {
+ SetAttribute(rids.release());
+ }
+ return true;
+}
+
+void
+SipccSdpAttributeList::LoadExtmap(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ auto extmaps = MakeUnique<SdpExtmapAttributeList>();
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_EXTMAP, i);
+
+ if (!attr) {
+ break;
+ }
+
+ sdp_extmap_t* extmap = &(attr->attr.extmap);
+
+ SdpDirectionAttribute::Direction dir = SdpDirectionAttribute::kSendrecv;
+
+ if (extmap->media_direction_specified) {
+ ConvertDirection(extmap->media_direction, &dir);
+ }
+
+ extmaps->PushEntry(extmap->id, dir, extmap->media_direction_specified,
+ extmap->uri, extmap->extension_attributes);
+ }
+
+ if (!extmaps->mExtmaps.empty()) {
+ if (!AtSessionLevel() &&
+ mSessionLevel->HasAttribute(SdpAttribute::kExtmapAttribute)) {
+ uint32_t lineNumber =
+ sdp_attr_line_number(sdp, SDP_ATTR_EXTMAP, level, 0, 1);
+ errorHolder.AddParseError(
+ lineNumber, "extmap attributes in both session and media level");
+ }
+ SetAttribute(extmaps.release());
+ }
+}
+
+void
+SipccSdpAttributeList::LoadRtcpFb(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ auto rtcpfbs = MakeUnique<SdpRtcpFbAttributeList>();
+
+ for (uint16_t i = 1; i < UINT16_MAX; ++i) {
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_RTCP_FB, i);
+
+ if (!attr) {
+ break;
+ }
+
+ sdp_fmtp_fb_t* rtcpfb = &attr->attr.rtcp_fb;
+
+ SdpRtcpFbAttributeList::Type type;
+ std::string parameter;
+
+ // Set type and parameter
+ switch (rtcpfb->feedback_type) {
+ case SDP_RTCP_FB_ACK:
+ type = SdpRtcpFbAttributeList::kAck;
+ switch (rtcpfb->param.ack) {
+ // TODO: sipcc doesn't seem to support ack with no following token.
+ // Issue 189.
+ case SDP_RTCP_FB_ACK_RPSI:
+ parameter = SdpRtcpFbAttributeList::rpsi;
+ break;
+ case SDP_RTCP_FB_ACK_APP:
+ parameter = SdpRtcpFbAttributeList::app;
+ break;
+ default:
+ // Type we don't care about, ignore.
+ continue;
+ }
+ break;
+ case SDP_RTCP_FB_CCM:
+ type = SdpRtcpFbAttributeList::kCcm;
+ switch (rtcpfb->param.ccm) {
+ case SDP_RTCP_FB_CCM_FIR:
+ parameter = SdpRtcpFbAttributeList::fir;
+ break;
+ case SDP_RTCP_FB_CCM_TMMBR:
+ parameter = SdpRtcpFbAttributeList::tmmbr;
+ break;
+ case SDP_RTCP_FB_CCM_TSTR:
+ parameter = SdpRtcpFbAttributeList::tstr;
+ break;
+ case SDP_RTCP_FB_CCM_VBCM:
+ parameter = SdpRtcpFbAttributeList::vbcm;
+ break;
+ default:
+ // Type we don't care about, ignore.
+ continue;
+ }
+ break;
+ case SDP_RTCP_FB_NACK:
+ type = SdpRtcpFbAttributeList::kNack;
+ switch (rtcpfb->param.nack) {
+ case SDP_RTCP_FB_NACK_BASIC:
+ break;
+ case SDP_RTCP_FB_NACK_SLI:
+ parameter = SdpRtcpFbAttributeList::sli;
+ break;
+ case SDP_RTCP_FB_NACK_PLI:
+ parameter = SdpRtcpFbAttributeList::pli;
+ break;
+ case SDP_RTCP_FB_NACK_RPSI:
+ parameter = SdpRtcpFbAttributeList::rpsi;
+ break;
+ case SDP_RTCP_FB_NACK_APP:
+ parameter = SdpRtcpFbAttributeList::app;
+ break;
+ default:
+ // Type we don't care about, ignore.
+ continue;
+ }
+ break;
+ case SDP_RTCP_FB_TRR_INT: {
+ type = SdpRtcpFbAttributeList::kTrrInt;
+ std::ostringstream os;
+ os << rtcpfb->param.trr_int;
+ parameter = os.str();
+ } break;
+ case SDP_RTCP_FB_REMB: {
+ type = SdpRtcpFbAttributeList::kRemb;
+ } break;
+ default:
+ // Type we don't care about, ignore.
+ continue;
+ }
+
+ std::stringstream osPayloadType;
+ if (rtcpfb->payload_num == UINT16_MAX) {
+ osPayloadType << "*";
+ } else {
+ osPayloadType << rtcpfb->payload_num;
+ }
+
+ std::string pt(osPayloadType.str());
+ std::string extra(rtcpfb->extra);
+
+ rtcpfbs->PushEntry(pt, type, parameter, extra);
+ }
+
+ if (!rtcpfbs->mFeedbacks.empty()) {
+ SetAttribute(rtcpfbs.release());
+ }
+}
+
+void
+SipccSdpAttributeList::LoadRtcp(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_RTCP, 1);
+
+ if (!attr) {
+ return;
+ }
+
+ sdp_rtcp_t* rtcp = &attr->attr.rtcp;
+
+ if (rtcp->nettype != SDP_NT_INTERNET) {
+ return;
+ }
+
+ if (rtcp->addrtype != SDP_AT_IP4 && rtcp->addrtype != SDP_AT_IP6) {
+ return;
+ }
+
+ if (!strlen(rtcp->addr)) {
+ SetAttribute(new SdpRtcpAttribute(rtcp->port));
+ } else {
+ SetAttribute(
+ new SdpRtcpAttribute(
+ rtcp->port,
+ sdp::kInternet,
+ rtcp->addrtype == SDP_AT_IP4 ? sdp::kIPv4 : sdp::kIPv6,
+ rtcp->addr));
+ }
+}
+
+bool
+SipccSdpAttributeList::Load(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+
+ LoadSimpleStrings(sdp, level, errorHolder);
+ LoadSimpleNumbers(sdp, level, errorHolder);
+ LoadFlags(sdp, level);
+ LoadDirection(sdp, level, errorHolder);
+
+ if (AtSessionLevel()) {
+ if (!LoadGroups(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ if (!LoadMsidSemantics(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ LoadIdentity(sdp, level);
+ LoadDtlsMessage(sdp, level);
+ } else {
+ sdp_media_e mtype = sdp_get_media_type(sdp, level);
+ if (mtype == SDP_MEDIA_APPLICATION) {
+ if (!LoadSctpmap(sdp, level, errorHolder)) {
+ return false;
+ }
+ } else {
+ if (!LoadRtpmap(sdp, level, errorHolder)) {
+ return false;
+ }
+ }
+ LoadCandidate(sdp, level);
+ LoadFmtp(sdp, level);
+ LoadMsids(sdp, level, errorHolder);
+ LoadRtcpFb(sdp, level, errorHolder);
+ LoadRtcp(sdp, level, errorHolder);
+ LoadSsrc(sdp, level);
+ if (!LoadImageattr(sdp, level, errorHolder)) {
+ return false;
+ }
+ if (!LoadSimulcast(sdp, level, errorHolder)) {
+ return false;
+ }
+ if (!LoadRid(sdp, level, errorHolder)) {
+ return false;
+ }
+ }
+
+ LoadIceAttributes(sdp, level);
+ if (!LoadFingerprint(sdp, level, errorHolder)) {
+ return false;
+ }
+ LoadSetup(sdp, level);
+ LoadExtmap(sdp, level, errorHolder);
+
+ return true;
+}
+
+bool
+SipccSdpAttributeList::IsAllowedHere(SdpAttribute::AttributeType type) const
+{
+ if (AtSessionLevel() && !SdpAttribute::IsAllowedAtSessionLevel(type)) {
+ return false;
+ }
+
+ if (!AtSessionLevel() && !SdpAttribute::IsAllowedAtMediaLevel(type)) {
+ return false;
+ }
+
+ return true;
+}
+
+void
+SipccSdpAttributeList::WarnAboutMisplacedAttribute(
+ SdpAttribute::AttributeType type, uint32_t lineNumber,
+ SdpErrorHolder& errorHolder)
+{
+ std::string warning = SdpAttribute::GetAttributeTypeString(type) +
+ (AtSessionLevel() ? " at session level. Ignoring."
+ : " at media level. Ignoring.");
+ errorHolder.AddParseError(lineNumber, warning);
+}
+
+const std::vector<std::string>&
+SipccSdpAttributeList::GetCandidate() const
+{
+ if (!HasAttribute(SdpAttribute::kCandidateAttribute)) {
+ MOZ_CRASH();
+ }
+
+ return static_cast<const SdpMultiStringAttribute*>(
+ GetAttribute(SdpAttribute::kCandidateAttribute))->mValues;
+}
+
+const SdpConnectionAttribute&
+SipccSdpAttributeList::GetConnection() const
+{
+ if (!HasAttribute(SdpAttribute::kConnectionAttribute)) {
+ MOZ_CRASH();
+ }
+
+ return *static_cast<const SdpConnectionAttribute*>(
+ GetAttribute(SdpAttribute::kConnectionAttribute));
+}
+
+SdpDirectionAttribute::Direction
+SipccSdpAttributeList::GetDirection() const
+{
+ if (!HasAttribute(SdpAttribute::kDirectionAttribute)) {
+ MOZ_CRASH();
+ }
+
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kDirectionAttribute);
+ return static_cast<const SdpDirectionAttribute*>(attr)->mValue;
+}
+
+const SdpDtlsMessageAttribute&
+SipccSdpAttributeList::GetDtlsMessage() const
+{
+ if (!HasAttribute(SdpAttribute::kDtlsMessageAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kDtlsMessageAttribute);
+ return *static_cast<const SdpDtlsMessageAttribute*>(attr);
+}
+
+const SdpExtmapAttributeList&
+SipccSdpAttributeList::GetExtmap() const
+{
+ if (!HasAttribute(SdpAttribute::kExtmapAttribute)) {
+ MOZ_CRASH();
+ }
+
+ return *static_cast<const SdpExtmapAttributeList*>(
+ GetAttribute(SdpAttribute::kExtmapAttribute));
+}
+
+const SdpFingerprintAttributeList&
+SipccSdpAttributeList::GetFingerprint() const
+{
+ if (!HasAttribute(SdpAttribute::kFingerprintAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kFingerprintAttribute);
+ return *static_cast<const SdpFingerprintAttributeList*>(attr);
+}
+
+const SdpFmtpAttributeList&
+SipccSdpAttributeList::GetFmtp() const
+{
+ if (!HasAttribute(SdpAttribute::kFmtpAttribute)) {
+ MOZ_CRASH();
+ }
+
+ return *static_cast<const SdpFmtpAttributeList*>(
+ GetAttribute(SdpAttribute::kFmtpAttribute));
+}
+
+const SdpGroupAttributeList&
+SipccSdpAttributeList::GetGroup() const
+{
+ if (!HasAttribute(SdpAttribute::kGroupAttribute)) {
+ MOZ_CRASH();
+ }
+
+ return *static_cast<const SdpGroupAttributeList*>(
+ GetAttribute(SdpAttribute::kGroupAttribute));
+}
+
+const SdpOptionsAttribute&
+SipccSdpAttributeList::GetIceOptions() const
+{
+ if (!HasAttribute(SdpAttribute::kIceOptionsAttribute)) {
+ MOZ_CRASH();
+ }
+
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceOptionsAttribute);
+ return *static_cast<const SdpOptionsAttribute*>(attr);
+}
+
+const std::string&
+SipccSdpAttributeList::GetIcePwd() const
+{
+ if (!HasAttribute(SdpAttribute::kIcePwdAttribute)) {
+ return kEmptyString;
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kIcePwdAttribute);
+ return static_cast<const SdpStringAttribute*>(attr)->mValue;
+}
+
+const std::string&
+SipccSdpAttributeList::GetIceUfrag() const
+{
+ if (!HasAttribute(SdpAttribute::kIceUfragAttribute)) {
+ return kEmptyString;
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceUfragAttribute);
+ return static_cast<const SdpStringAttribute*>(attr)->mValue;
+}
+
+const std::string&
+SipccSdpAttributeList::GetIdentity() const
+{
+ if (!HasAttribute(SdpAttribute::kIdentityAttribute)) {
+ return kEmptyString;
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kIdentityAttribute);
+ return static_cast<const SdpStringAttribute*>(attr)->mValue;
+}
+
+const SdpImageattrAttributeList&
+SipccSdpAttributeList::GetImageattr() const
+{
+ if (!HasAttribute(SdpAttribute::kImageattrAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kImageattrAttribute);
+ return *static_cast<const SdpImageattrAttributeList*>(attr);
+}
+
+const SdpSimulcastAttribute&
+SipccSdpAttributeList::GetSimulcast() const
+{
+ if (!HasAttribute(SdpAttribute::kSimulcastAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kSimulcastAttribute);
+ return *static_cast<const SdpSimulcastAttribute*>(attr);
+}
+
+const std::string&
+SipccSdpAttributeList::GetLabel() const
+{
+ if (!HasAttribute(SdpAttribute::kLabelAttribute)) {
+ return kEmptyString;
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kLabelAttribute);
+ return static_cast<const SdpStringAttribute*>(attr)->mValue;
+}
+
+uint32_t
+SipccSdpAttributeList::GetMaxptime() const
+{
+ if (!HasAttribute(SdpAttribute::kMaxptimeAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kMaxptimeAttribute);
+ return static_cast<const SdpNumberAttribute*>(attr)->mValue;
+}
+
+const std::string&
+SipccSdpAttributeList::GetMid() const
+{
+ if (!HasAttribute(SdpAttribute::kMidAttribute)) {
+ return kEmptyString;
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kMidAttribute);
+ return static_cast<const SdpStringAttribute*>(attr)->mValue;
+}
+
+const SdpMsidAttributeList&
+SipccSdpAttributeList::GetMsid() const
+{
+ if (!HasAttribute(SdpAttribute::kMsidAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidAttribute);
+ return *static_cast<const SdpMsidAttributeList*>(attr);
+}
+
+const SdpMsidSemanticAttributeList&
+SipccSdpAttributeList::GetMsidSemantic() const
+{
+ if (!HasAttribute(SdpAttribute::kMsidSemanticAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidSemanticAttribute);
+ return *static_cast<const SdpMsidSemanticAttributeList*>(attr);
+}
+
+const SdpRidAttributeList&
+SipccSdpAttributeList::GetRid() const
+{
+ if (!HasAttribute(SdpAttribute::kRidAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kRidAttribute);
+ return *static_cast<const SdpRidAttributeList*>(attr);
+}
+
+uint32_t
+SipccSdpAttributeList::GetPtime() const
+{
+ if (!HasAttribute(SdpAttribute::kPtimeAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kPtimeAttribute);
+ return static_cast<const SdpNumberAttribute*>(attr)->mValue;
+}
+
+const SdpRtcpAttribute&
+SipccSdpAttributeList::GetRtcp() const
+{
+ if (!HasAttribute(SdpAttribute::kRtcpAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpAttribute);
+ return *static_cast<const SdpRtcpAttribute*>(attr);
+}
+
+const SdpRtcpFbAttributeList&
+SipccSdpAttributeList::GetRtcpFb() const
+{
+ if (!HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpFbAttribute);
+ return *static_cast<const SdpRtcpFbAttributeList*>(attr);
+}
+
+const SdpRemoteCandidatesAttribute&
+SipccSdpAttributeList::GetRemoteCandidates() const
+{
+ MOZ_CRASH("Not yet implemented");
+}
+
+const SdpRtpmapAttributeList&
+SipccSdpAttributeList::GetRtpmap() const
+{
+ if (!HasAttribute(SdpAttribute::kRtpmapAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtpmapAttribute);
+ return *static_cast<const SdpRtpmapAttributeList*>(attr);
+}
+
+const SdpSctpmapAttributeList&
+SipccSdpAttributeList::GetSctpmap() const
+{
+ if (!HasAttribute(SdpAttribute::kSctpmapAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpmapAttribute);
+ return *static_cast<const SdpSctpmapAttributeList*>(attr);
+}
+
+const SdpSetupAttribute&
+SipccSdpAttributeList::GetSetup() const
+{
+ if (!HasAttribute(SdpAttribute::kSetupAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kSetupAttribute);
+ return *static_cast<const SdpSetupAttribute*>(attr);
+}
+
+const SdpSsrcAttributeList&
+SipccSdpAttributeList::GetSsrc() const
+{
+ if (!HasAttribute(SdpAttribute::kSsrcAttribute)) {
+ MOZ_CRASH();
+ }
+ const SdpAttribute* attr = GetAttribute(SdpAttribute::kSsrcAttribute);
+ return *static_cast<const SdpSsrcAttributeList*>(attr);
+}
+
+const SdpSsrcGroupAttributeList&
+SipccSdpAttributeList::GetSsrcGroup() const
+{
+ MOZ_CRASH("Not yet implemented");
+}
+
+void
+SipccSdpAttributeList::Serialize(std::ostream& os) const
+{
+ for (size_t i = 0; i < kNumAttributeTypes; ++i) {
+ if (mAttributes[i]) {
+ os << *mAttributes[i];
+ }
+ }
+}
+
+} // namespace mozilla
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h
new file mode 100644
index 000000000..62dded52e
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpAttributeList.h
@@ -0,0 +1,147 @@
+/* -*- 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 _SIPCCSDPATTRIBUTELIST_H_
+#define _SIPCCSDPATTRIBUTELIST_H_
+
+#include "signaling/src/sdp/SdpAttributeList.h"
+
+extern "C" {
+#include "signaling/src/sdp/sipcc/sdp.h"
+}
+
+namespace mozilla
+{
+
+class SipccSdp;
+class SipccSdpMediaSection;
+class SdpErrorHolder;
+
+class SipccSdpAttributeList : public SdpAttributeList
+{
+ friend class SipccSdpMediaSection;
+ friend class SipccSdp;
+
+public:
+ // Make sure we don't hide the default arg thunks
+ using SdpAttributeList::HasAttribute;
+ using SdpAttributeList::GetAttribute;
+
+ virtual bool HasAttribute(AttributeType type,
+ bool sessionFallback) const override;
+ virtual const SdpAttribute* GetAttribute(
+ AttributeType type, bool sessionFallback) const override;
+ virtual void SetAttribute(SdpAttribute* attr) override;
+ virtual void RemoveAttribute(AttributeType type) override;
+ virtual void Clear() override;
+
+ virtual const SdpConnectionAttribute& GetConnection() const override;
+ virtual const SdpFingerprintAttributeList& GetFingerprint() const
+ override;
+ virtual const SdpGroupAttributeList& GetGroup() const override;
+ virtual const SdpOptionsAttribute& GetIceOptions() const override;
+ virtual const SdpRtcpAttribute& GetRtcp() const override;
+ virtual const SdpRemoteCandidatesAttribute& GetRemoteCandidates() const
+ override;
+ virtual const SdpSetupAttribute& GetSetup() const override;
+ virtual const SdpSsrcAttributeList& GetSsrc() const override;
+ virtual const SdpSsrcGroupAttributeList& GetSsrcGroup() const override;
+ virtual const SdpDtlsMessageAttribute& GetDtlsMessage() const override;
+
+ // These attributes can appear multiple times, so the returned
+ // classes actually represent a collection of values.
+ virtual const std::vector<std::string>& GetCandidate() const override;
+ virtual const SdpExtmapAttributeList& GetExtmap() const override;
+ virtual const SdpFmtpAttributeList& GetFmtp() const override;
+ virtual const SdpImageattrAttributeList& GetImageattr() const override;
+ const SdpSimulcastAttribute& GetSimulcast() const override;
+ virtual const SdpMsidAttributeList& GetMsid() const override;
+ virtual const SdpMsidSemanticAttributeList& GetMsidSemantic()
+ const override;
+ const SdpRidAttributeList& GetRid() const override;
+ virtual const SdpRtcpFbAttributeList& GetRtcpFb() const override;
+ virtual const SdpRtpmapAttributeList& GetRtpmap() const override;
+ virtual const SdpSctpmapAttributeList& GetSctpmap() const override;
+
+ // These attributes are effectively simple types, so we'll make life
+ // easy by just returning their value.
+ virtual const std::string& GetIcePwd() const override;
+ virtual const std::string& GetIceUfrag() const override;
+ virtual const std::string& GetIdentity() const override;
+ virtual const std::string& GetLabel() const override;
+ virtual unsigned int GetMaxptime() const override;
+ virtual const std::string& GetMid() const override;
+ virtual unsigned int GetPtime() const override;
+
+ virtual SdpDirectionAttribute::Direction GetDirection() const override;
+
+ virtual void Serialize(std::ostream&) const override;
+
+ virtual ~SipccSdpAttributeList();
+
+private:
+ static const std::string kEmptyString;
+ static const size_t kNumAttributeTypes = SdpAttribute::kLastAttribute + 1;
+
+ // Pass a session-level attribute list if constructing a media-level one,
+ // otherwise pass nullptr
+ explicit SipccSdpAttributeList(const SipccSdpAttributeList* sessionLevel);
+
+ bool Load(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadSimpleStrings(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder);
+ void LoadSimpleString(sdp_t* sdp, uint16_t level, sdp_attr_e attr,
+ AttributeType targetType, SdpErrorHolder& errorHolder);
+ void LoadSimpleNumbers(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder);
+ void LoadSimpleNumber(sdp_t* sdp, uint16_t level, sdp_attr_e attr,
+ AttributeType targetType, SdpErrorHolder& errorHolder);
+ void LoadFlags(sdp_t* sdp, uint16_t level);
+ void LoadDirection(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadRtpmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadSctpmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadIceAttributes(sdp_t* sdp, uint16_t level);
+ bool LoadFingerprint(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadCandidate(sdp_t* sdp, uint16_t level);
+ void LoadSetup(sdp_t* sdp, uint16_t level);
+ void LoadSsrc(sdp_t* sdp, uint16_t level);
+ bool LoadImageattr(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadSimulcast(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadGroups(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadMsidSemantics(sdp_t* sdp,
+ uint16_t level,
+ SdpErrorHolder& errorHolder);
+ void LoadIdentity(sdp_t* sdp, uint16_t level);
+ void LoadDtlsMessage(sdp_t* sdp, uint16_t level);
+ void LoadFmtp(sdp_t* sdp, uint16_t level);
+ void LoadMsids(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadRid(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadExtmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadRtcpFb(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void LoadRtcp(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ static SdpRtpmapAttributeList::CodecType GetCodecType(rtp_ptype type);
+
+ bool
+ AtSessionLevel() const
+ {
+ return !mSessionLevel;
+ }
+ bool IsAllowedHere(SdpAttribute::AttributeType type) const;
+ void WarnAboutMisplacedAttribute(SdpAttribute::AttributeType type,
+ uint32_t lineNumber,
+ SdpErrorHolder& errorHolder);
+
+ const SipccSdpAttributeList* mSessionLevel;
+
+ SdpAttribute* mAttributes[kNumAttributeTypes];
+
+ SipccSdpAttributeList(const SipccSdpAttributeList& orig) = delete;
+ SipccSdpAttributeList& operator=(const SipccSdpAttributeList& rhs) = delete;
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp
new file mode 100644
index 000000000..33c2a9e0d
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.cpp
@@ -0,0 +1,423 @@
+/* -*- 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/. */
+
+#include "signaling/src/sdp/SipccSdpMediaSection.h"
+
+#include <ostream>
+#include "signaling/src/sdp/SdpErrorHolder.h"
+
+#ifdef CRLF
+#undef CRLF
+#endif
+#define CRLF "\r\n"
+
+namespace mozilla
+{
+
+unsigned int
+SipccSdpMediaSection::GetPort() const
+{
+ return mPort;
+}
+
+void
+SipccSdpMediaSection::SetPort(unsigned int port)
+{
+ mPort = port;
+}
+
+unsigned int
+SipccSdpMediaSection::GetPortCount() const
+{
+ return mPortCount;
+}
+
+SdpMediaSection::Protocol
+SipccSdpMediaSection::GetProtocol() const
+{
+ return mProtocol;
+}
+
+const SdpConnection&
+SipccSdpMediaSection::GetConnection() const
+{
+ return *mConnection;
+}
+
+SdpConnection&
+SipccSdpMediaSection::GetConnection()
+{
+ return *mConnection;
+}
+
+uint32_t
+SipccSdpMediaSection::GetBandwidth(const std::string& type) const
+{
+ auto found = mBandwidths.find(type);
+ if (found == mBandwidths.end()) {
+ return 0;
+ }
+ return found->second;
+}
+
+const std::vector<std::string>&
+SipccSdpMediaSection::GetFormats() const
+{
+ return mFormats;
+}
+
+const SdpAttributeList&
+SipccSdpMediaSection::GetAttributeList() const
+{
+ return mAttributeList;
+}
+
+SdpAttributeList&
+SipccSdpMediaSection::GetAttributeList()
+{
+ return mAttributeList;
+}
+
+SdpDirectionAttribute
+SipccSdpMediaSection::GetDirectionAttribute() const
+{
+ return SdpDirectionAttribute(mAttributeList.GetDirection());
+}
+
+bool
+SipccSdpMediaSection::Load(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ switch (sdp_get_media_type(sdp, level)) {
+ case SDP_MEDIA_AUDIO:
+ mMediaType = kAudio;
+ break;
+ case SDP_MEDIA_VIDEO:
+ mMediaType = kVideo;
+ break;
+ case SDP_MEDIA_APPLICATION:
+ mMediaType = kApplication;
+ break;
+ case SDP_MEDIA_TEXT:
+ mMediaType = kText;
+ break;
+
+ default:
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported media section type");
+ return false;
+ }
+
+ mPort = sdp_get_media_portnum(sdp, level);
+ int32_t pc = sdp_get_media_portcount(sdp, level);
+ if (pc == SDP_INVALID_VALUE) {
+ // SDP_INVALID_VALUE (ie; -2) is used when there is no port count. :(
+ mPortCount = 0;
+ } else if (pc > static_cast<int32_t>(UINT16_MAX) || pc < 0) {
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Invalid port count");
+ return false;
+ } else {
+ mPortCount = pc;
+ }
+
+ if (!LoadProtocol(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ if (!LoadFormats(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ if (!mAttributeList.Load(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ if (!ValidateSimulcast(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ if (!mBandwidths.Load(sdp, level, errorHolder)) {
+ return false;
+ }
+
+ return LoadConnection(sdp, level, errorHolder);
+}
+
+bool
+SipccSdpMediaSection::LoadProtocol(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ switch (sdp_get_media_transport(sdp, level)) {
+ case SDP_TRANSPORT_RTPAVP:
+ mProtocol = kRtpAvp;
+ break;
+ case SDP_TRANSPORT_RTPSAVP:
+ mProtocol = kRtpSavp;
+ break;
+ case SDP_TRANSPORT_RTPAVPF:
+ mProtocol = kRtpAvpf;
+ break;
+ case SDP_TRANSPORT_RTPSAVPF:
+ mProtocol = kRtpSavpf;
+ break;
+ case SDP_TRANSPORT_UDPTLSRTPSAVP:
+ mProtocol = kUdpTlsRtpSavp;
+ break;
+ case SDP_TRANSPORT_UDPTLSRTPSAVPF:
+ mProtocol = kUdpTlsRtpSavpf;
+ break;
+ case SDP_TRANSPORT_TCPTLSRTPSAVP:
+ mProtocol = kTcpTlsRtpSavp;
+ break;
+ case SDP_TRANSPORT_TCPTLSRTPSAVPF:
+ mProtocol = kTcpTlsRtpSavpf;
+ break;
+ case SDP_TRANSPORT_DTLSSCTP:
+ mProtocol = kDtlsSctp;
+ break;
+
+ default:
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported media transport type");
+ return false;
+ }
+ return true;
+}
+
+bool
+SipccSdpMediaSection::LoadFormats(sdp_t* sdp,
+ uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ sdp_media_e mtype = sdp_get_media_type(sdp, level);
+
+ if (mtype == SDP_MEDIA_APPLICATION) {
+ uint32_t ptype = sdp_get_media_sctp_port(sdp, level);
+ std::ostringstream osPayloadType;
+ osPayloadType << ptype;
+ mFormats.push_back(osPayloadType.str());
+ } else if (mtype == SDP_MEDIA_AUDIO || mtype == SDP_MEDIA_VIDEO) {
+ uint16_t count = sdp_get_media_num_payload_types(sdp, level);
+ for (uint16_t i = 0; i < count; ++i) {
+ sdp_payload_ind_e indicator; // we ignore this, which is fine
+ uint32_t ptype =
+ sdp_get_media_payload_type(sdp, level, i + 1, &indicator);
+
+ if (GET_DYN_PAYLOAD_TYPE_VALUE(ptype) > UINT8_MAX) {
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Format is too large");
+ return false;
+ }
+
+ std::ostringstream osPayloadType;
+ // sipcc stores payload types in a funny way. When sipcc and the SDP it
+ // parsed differ on what payload type number should be used for a given
+ // codec, sipcc's value goes in the lower byte, and the SDP's value in
+ // the upper byte. When they do not differ, only the lower byte is used.
+ // We want what was in the SDP, verbatim.
+ osPayloadType << GET_DYN_PAYLOAD_TYPE_VALUE(ptype);
+ mFormats.push_back(osPayloadType.str());
+ }
+ }
+
+ return true;
+}
+
+bool
+SipccSdpMediaSection::ValidateSimulcast(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder) const
+{
+ if (!GetAttributeList().HasAttribute(SdpAttribute::kSimulcastAttribute)) {
+ return true;
+ }
+
+ const SdpSimulcastAttribute& simulcast(GetAttributeList().GetSimulcast());
+ if (!ValidateSimulcastVersions(
+ sdp, level, simulcast.sendVersions, sdp::kSend, errorHolder)) {
+ return false;
+ }
+ if (!ValidateSimulcastVersions(
+ sdp, level, simulcast.recvVersions, sdp::kRecv, errorHolder)) {
+ return false;
+ }
+ return true;
+}
+
+bool
+SipccSdpMediaSection::ValidateSimulcastVersions(
+ sdp_t* sdp,
+ uint16_t level,
+ const SdpSimulcastAttribute::Versions& versions,
+ sdp::Direction direction,
+ SdpErrorHolder& errorHolder) const
+{
+ if (versions.IsSet() && !(direction & GetDirectionAttribute().mValue)) {
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "simulcast attribute has a direction that is "
+ "inconsistent with the direction of this media "
+ "section.");
+ return false;
+ }
+
+ for (const SdpSimulcastAttribute::Version& version : versions) {
+ for (const std::string& id : version.choices) {
+ if (versions.type == SdpSimulcastAttribute::Versions::kRid) {
+ const SdpRidAttributeList::Rid* ridAttr = FindRid(id);
+ if (!ridAttr || (ridAttr->direction != direction)) {
+ std::ostringstream os;
+ os << "No rid attribute for \'" << id << "\'";
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ os.str());
+ return false;
+ }
+ } else if (versions.type == SdpSimulcastAttribute::Versions::kPt) {
+ if (std::find(mFormats.begin(), mFormats.end(), id)
+ == mFormats.end()) {
+ std::ostringstream os;
+ os << "No pt for \'" << id << "\'";
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ os.str());
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool
+SipccSdpMediaSection::LoadConnection(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder)
+{
+ if (!sdp_connection_valid(sdp, level)) {
+ level = SDP_SESSION_LEVEL;
+ if (!sdp_connection_valid(sdp, level)) {
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Missing c= line");
+ return false;
+ }
+ }
+
+ sdp_nettype_e type = sdp_get_conn_nettype(sdp, level);
+ if (type != SDP_NT_INTERNET) {
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported network type");
+ return false;
+ }
+
+ sdp::AddrType addrType;
+ switch (sdp_get_conn_addrtype(sdp, level)) {
+ case SDP_AT_IP4:
+ addrType = sdp::kIPv4;
+ break;
+ case SDP_AT_IP6:
+ addrType = sdp::kIPv6;
+ break;
+ default:
+ errorHolder.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported address type");
+ return false;
+ }
+
+ std::string address = sdp_get_conn_address(sdp, level);
+ int16_t ttl = static_cast<uint16_t>(sdp_get_mcast_ttl(sdp, level));
+ if (ttl < 0) {
+ ttl = 0;
+ }
+ int32_t numAddr =
+ static_cast<uint32_t>(sdp_get_mcast_num_of_addresses(sdp, level));
+ if (numAddr < 0) {
+ numAddr = 0;
+ }
+ mConnection = MakeUnique<SdpConnection>(addrType, address, ttl, numAddr);
+ return true;
+}
+
+void
+SipccSdpMediaSection::AddCodec(const std::string& pt, const std::string& name,
+ uint32_t clockrate, uint16_t channels)
+{
+ mFormats.push_back(pt);
+
+ SdpRtpmapAttributeList* rtpmap = new SdpRtpmapAttributeList();
+ if (mAttributeList.HasAttribute(SdpAttribute::kRtpmapAttribute)) {
+ const SdpRtpmapAttributeList& old = mAttributeList.GetRtpmap();
+ for (auto it = old.mRtpmaps.begin(); it != old.mRtpmaps.end(); ++it) {
+ rtpmap->mRtpmaps.push_back(*it);
+ }
+ }
+ SdpRtpmapAttributeList::CodecType codec = SdpRtpmapAttributeList::kOtherCodec;
+ if (name == "opus") {
+ codec = SdpRtpmapAttributeList::kOpus;
+ } else if (name == "G722") {
+ codec = SdpRtpmapAttributeList::kG722;
+ } else if (name == "PCMU") {
+ codec = SdpRtpmapAttributeList::kPCMU;
+ } else if (name == "PCMA") {
+ codec = SdpRtpmapAttributeList::kPCMA;
+ } else if (name == "VP8") {
+ codec = SdpRtpmapAttributeList::kVP8;
+ } else if (name == "VP9") {
+ codec = SdpRtpmapAttributeList::kVP9;
+ } else if (name == "H264") {
+ codec = SdpRtpmapAttributeList::kH264;
+ }
+
+ rtpmap->PushEntry(pt, codec, name, clockrate, channels);
+ mAttributeList.SetAttribute(rtpmap);
+}
+
+void
+SipccSdpMediaSection::ClearCodecs()
+{
+ mFormats.clear();
+ mAttributeList.RemoveAttribute(SdpAttribute::kRtpmapAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kFmtpAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kSctpmapAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
+}
+
+void
+SipccSdpMediaSection::AddDataChannel(const std::string& pt,
+ const std::string& name, uint16_t streams)
+{
+ // Only one allowed, for now. This may change as the specs (and deployments)
+ // evolve.
+ mFormats.clear();
+ mFormats.push_back(pt);
+ SdpSctpmapAttributeList* sctpmap = new SdpSctpmapAttributeList();
+ sctpmap->PushEntry(pt, name, streams);
+ mAttributeList.SetAttribute(sctpmap);
+}
+
+void
+SipccSdpMediaSection::Serialize(std::ostream& os) const
+{
+ os << "m=" << mMediaType << " " << mPort;
+ if (mPortCount) {
+ os << "/" << mPortCount;
+ }
+ os << " " << mProtocol;
+ for (auto i = mFormats.begin(); i != mFormats.end(); ++i) {
+ os << " " << (*i);
+ }
+ os << CRLF;
+
+ // We dont do i=
+
+ if (mConnection) {
+ os << *mConnection;
+ }
+
+ mBandwidths.Serialize(os);
+
+ // We dont do k= because they're evil
+
+ os << mAttributeList;
+}
+
+} // namespace mozilla
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h
new file mode 100644
index 000000000..6d2dafa7b
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpMediaSection.h
@@ -0,0 +1,102 @@
+/* -*- 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 _SIPCCSDPMEDIASECTION_H_
+#define _SIPCCSDPMEDIASECTION_H_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
+#include "signaling/src/sdp/SdpMediaSection.h"
+#include "signaling/src/sdp/SipccSdpAttributeList.h"
+
+#include <map>
+
+extern "C" {
+#include "signaling/src/sdp/sipcc/sdp.h"
+}
+
+namespace mozilla
+{
+
+class SipccSdp;
+class SdpErrorHolder;
+
+class SipccSdpBandwidths final : public std::map<std::string, uint32_t>
+{
+public:
+ bool Load(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ void Serialize(std::ostream& os) const;
+};
+
+class SipccSdpMediaSection final : public SdpMediaSection
+{
+ friend class SipccSdp;
+
+public:
+ ~SipccSdpMediaSection() {}
+
+ virtual MediaType
+ GetMediaType() const override
+ {
+ return mMediaType;
+ }
+
+ virtual unsigned int GetPort() const override;
+ virtual void SetPort(unsigned int port) override;
+ virtual unsigned int GetPortCount() const override;
+ virtual Protocol GetProtocol() const override;
+ virtual const SdpConnection& GetConnection() const override;
+ virtual SdpConnection& GetConnection() override;
+ virtual uint32_t GetBandwidth(const std::string& type) const override;
+ virtual const std::vector<std::string>& GetFormats() const override;
+
+ virtual const SdpAttributeList& GetAttributeList() const override;
+ virtual SdpAttributeList& GetAttributeList() override;
+ virtual SdpDirectionAttribute GetDirectionAttribute() const override;
+
+ virtual void AddCodec(const std::string& pt, const std::string& name,
+ uint32_t clockrate, uint16_t channels) override;
+ virtual void ClearCodecs() override;
+
+ virtual void AddDataChannel(const std::string& pt, const std::string& name,
+ uint16_t streams) override;
+
+ virtual void Serialize(std::ostream&) const override;
+
+private:
+ SipccSdpMediaSection(size_t level, const SipccSdpAttributeList* sessionLevel)
+ : SdpMediaSection(level), mAttributeList(sessionLevel)
+ {
+ }
+
+ bool Load(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadConnection(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadProtocol(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool LoadFormats(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder);
+ bool ValidateSimulcast(sdp_t* sdp, uint16_t level,
+ SdpErrorHolder& errorHolder) const;
+ bool ValidateSimulcastVersions(
+ sdp_t* sdp,
+ uint16_t level,
+ const SdpSimulcastAttribute::Versions& versions,
+ sdp::Direction direction,
+ SdpErrorHolder& errorHolder) const;
+
+ // the following values are cached on first get
+ MediaType mMediaType;
+ uint16_t mPort;
+ uint16_t mPortCount;
+ Protocol mProtocol;
+ std::vector<std::string> mFormats;
+
+ UniquePtr<SdpConnection> mConnection;
+ SipccSdpBandwidths mBandwidths;
+
+ SipccSdpAttributeList mAttributeList;
+};
+}
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpParser.cpp b/media/webrtc/signaling/src/sdp/SipccSdpParser.cpp
new file mode 100644
index 000000000..04fea305c
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpParser.cpp
@@ -0,0 +1,83 @@
+/* -*- 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/. */
+
+#include "signaling/src/sdp/SipccSdpParser.h"
+#include "signaling/src/sdp/SipccSdp.h"
+
+#include <utility>
+extern "C" {
+#include "signaling/src/sdp/sipcc/sdp.h"
+}
+
+namespace mozilla
+{
+
+extern "C" {
+
+void
+sipcc_sdp_parser_error_handler(void *context, uint32_t line,
+ const char *message)
+{
+ SdpErrorHolder *errorHolder = static_cast<SdpErrorHolder *>(context);
+ std::string err(message);
+ errorHolder->AddParseError(line, err);
+}
+
+} // extern "C"
+
+UniquePtr<Sdp>
+SipccSdpParser::Parse(const std::string &sdpText)
+{
+ ClearParseErrors();
+
+ sdp_conf_options_t *sipcc_config = sdp_init_config();
+ if (!sipcc_config) {
+ return UniquePtr<Sdp>();
+ }
+
+ sdp_nettype_supported(sipcc_config, SDP_NT_INTERNET, true);
+ sdp_addrtype_supported(sipcc_config, SDP_AT_IP4, true);
+ sdp_addrtype_supported(sipcc_config, SDP_AT_IP6, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPAVP, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPAVPF, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPSAVP, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPSAVPF, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_UDPTLSRTPSAVP, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_UDPTLSRTPSAVPF, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_TCPTLSRTPSAVP, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_TCPTLSRTPSAVPF, true);
+ sdp_transport_supported(sipcc_config, SDP_TRANSPORT_DTLSSCTP, true);
+ sdp_require_session_name(sipcc_config, false);
+
+ sdp_config_set_error_handler(sipcc_config, &sipcc_sdp_parser_error_handler,
+ this);
+
+ // Takes ownership of |sipcc_config| iff it succeeds
+ sdp_t *sdp = sdp_init_description(sipcc_config);
+ if (!sdp) {
+ sdp_free_config(sipcc_config);
+ return UniquePtr<Sdp>();
+ }
+
+ const char *rawString = sdpText.c_str();
+ sdp_result_e sdpres = sdp_parse(sdp, rawString, sdpText.length());
+ if (sdpres != SDP_SUCCESS) {
+ sdp_free_description(sdp);
+ return UniquePtr<Sdp>();
+ }
+
+ UniquePtr<SipccSdp> sipccSdp(new SipccSdp);
+
+ bool success = sipccSdp->Load(sdp, *this);
+ sdp_free_description(sdp);
+ if (!success) {
+ return UniquePtr<Sdp>();
+ }
+
+ return UniquePtr<Sdp>(Move(sipccSdp));
+}
+
+} // namespace mozilla
diff --git a/media/webrtc/signaling/src/sdp/SipccSdpParser.h b/media/webrtc/signaling/src/sdp/SipccSdpParser.h
new file mode 100644
index 000000000..f28780ddf
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/SipccSdpParser.h
@@ -0,0 +1,35 @@
+/* -*- 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 _SIPCCSDPPARSER_H_
+#define _SIPCCSDPPARSER_H_
+
+#include <string>
+
+#include "mozilla/UniquePtr.h"
+
+#include "signaling/src/sdp/Sdp.h"
+#include "signaling/src/sdp/SdpErrorHolder.h"
+
+namespace mozilla
+{
+
+class SipccSdpParser final : public SdpErrorHolder
+{
+public:
+ SipccSdpParser() {}
+ virtual ~SipccSdpParser() {}
+
+ /**
+ * This parses the provided text into an SDP object.
+ * This returns a nullptr-valued pointer if things go poorly.
+ */
+ UniquePtr<Sdp> Parse(const std::string& sdpText);
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/ccsdp.h b/media/webrtc/signaling/src/sdp/sipcc/ccsdp.h
new file mode 100644
index 000000000..8a04d8f0b
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/ccsdp.h
@@ -0,0 +1,207 @@
+/* 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 __CCSDP_H__
+#define __CCSDP_H__
+
+#include "cpr_types.h"
+#include "ccsdp_rtcp_fb.h"
+
+#define SIPSDP_ILBC_MODE20 20
+
+/**
+ * Return codes for sdp helper APIs
+ */
+typedef enum rtp_ptype_
+{
+ RTP_NONE = -1,
+ RTP_PCMU = 0,
+ RTP_CELP = 1,
+ RTP_G726 = 2,
+ RTP_GSM = 3,
+ RTP_G723 = 4,
+ RTP_DVI4 = 5,
+ RTP_DVI4_II = 6,
+ RTP_LPC = 7,
+ RTP_PCMA = 8,
+ RTP_G722 = 9,
+ RTP_G728 = 15,
+ RTP_G729 = 18,
+ RTP_JPEG = 26,
+ RTP_NV = 28,
+ RTP_H261 = 31,
+ RTP_H264_P0 = 97,
+ RTP_H264_P1 = 126,
+ RTP_TELEPHONE_EVENT = 101,
+ RTP_L16 = 102,
+ RTP_H263 = 103,
+ RTP_ILBC = 116, /* used only to make an offer */
+ RTP_OPUS = 109,
+ RTP_VP8 = 120,
+ RTP_VP9 = 121,
+ RTP_RED = 122,
+ RTP_ULPFEC = 123,
+ RTP_I420 = 124,
+ RTP_ISAC = 124
+} rtp_ptype;
+
+typedef struct {
+ const char *name;
+ int value;
+} ccsdp_key_table_entry_t;
+
+typedef enum max_coded_audio_bandwidth_ {
+ opus_nb = 0, /* Narrowband */
+ opus_mb = 1, /* Mediumband */
+ opus_wb = 2, /* Wideband */
+ opus_swb = 3, /* Super-wideband */
+ opus_fb = 4 /* Fullband */
+} max_coded_audio_bandwidth;
+
+static const ccsdp_key_table_entry_t max_coded_audio_bandwidth_table[] = {
+ {"nb", opus_nb},
+ {"mb", opus_mb},
+ {"wb", opus_wb},
+ {"swb", opus_swb},
+ {"fb", opus_fb}
+};
+
+typedef enum {
+ SDP_SUCCESS, /**< Success */
+ SDP_FAILURE,
+ SDP_INVALID_SDP_PTR,
+ SDP_NOT_SDP_DESCRIPTION,
+ SDP_INVALID_TOKEN_ORDERING,
+ SDP_INVALID_PARAMETER,
+ SDP_INVALID_MEDIA_LEVEL,
+ SDP_INVALID_CAPABILITY,
+ SDP_NO_RESOURCE,
+ SDP_UNRECOGNIZED_TOKEN,
+ SDP_NULL_BUF_PTR,
+ SDP_POTENTIAL_SDP_OVERFLOW,
+ SDP_EMPTY_TOKEN,
+ SDP_MAX_RC
+} sdp_result_e;
+
+/**
+ * Indicates invalid bandwidth value
+ */
+#define SDP_INVALID_VALUE (-2)
+
+/**
+ * Bandwidth modifier type for b= SDP line
+ */
+typedef enum {
+ SDP_BW_MODIFIER_INVALID = -1,
+ SDP_BW_MODIFIER_AS, /** < b=AS: */
+ SDP_BW_MODIFIER_CT, /** < b=CT: */
+ SDP_BW_MODIFIER_TIAS, /** < b=TIAS: */
+ SDP_MAX_BW_MODIFIER_VAL,
+ SDP_BW_MODIFIER_UNSUPPORTED
+} sdp_bw_modifier_e;
+
+/**
+ * SDP attribute types
+ */
+/* Attribute Types */
+typedef enum {
+ SDP_ATTR_BEARER = 0,
+ SDP_ATTR_CALLED,
+ SDP_ATTR_CONN_TYPE,
+ SDP_ATTR_DIALED,
+ SDP_ATTR_DIALING,
+ SDP_ATTR_DIRECTION,
+ SDP_ATTR_EECID,
+ SDP_ATTR_FMTP,
+ SDP_ATTR_SCTPMAP,
+ SDP_ATTR_FRAMING,
+ SDP_ATTR_INACTIVE,
+ SDP_ATTR_PTIME,
+ SDP_ATTR_QOS,
+ SDP_ATTR_CURR,
+ SDP_ATTR_DES,
+ SDP_ATTR_CONF,
+ SDP_ATTR_RECVONLY,
+ SDP_ATTR_RTPMAP,
+ SDP_ATTR_SECURE,
+ SDP_ATTR_SENDONLY,
+ SDP_ATTR_SENDRECV,
+ SDP_ATTR_SUBNET,
+ SDP_ATTR_T38_VERSION,
+ SDP_ATTR_T38_MAXBITRATE,
+ SDP_ATTR_T38_FILLBITREMOVAL,
+ SDP_ATTR_T38_TRANSCODINGMMR,
+ SDP_ATTR_T38_TRANSCODINGJBIG,
+ SDP_ATTR_T38_RATEMGMT,
+ SDP_ATTR_T38_MAXBUFFER,
+ SDP_ATTR_T38_MAXDGRAM,
+ SDP_ATTR_T38_UDPEC,
+ SDP_ATTR_X_CAP,
+ SDP_ATTR_X_CPAR,
+ SDP_ATTR_X_PC_CODEC,
+ SDP_ATTR_X_PC_QOS,
+ SDP_ATTR_X_QOS,
+ SDP_ATTR_X_SQN,
+ SDP_ATTR_TMRGWXID,
+ SDP_ATTR_TC1_PAYLOAD_BYTES,
+ SDP_ATTR_TC1_WINDOW_SIZE,
+ SDP_ATTR_TC2_PAYLOAD_BYTES,
+ SDP_ATTR_TC2_WINDOW_SIZE,
+ SDP_ATTR_RTCP,
+ SDP_ATTR_RTR,
+ SDP_ATTR_SILENCESUPP,
+ SDP_ATTR_SRTP_CONTEXT, /* version 2 sdescriptions */
+ SDP_ATTR_MPTIME,
+ SDP_ATTR_X_SIDIN,
+ SDP_ATTR_X_SIDOUT,
+ SDP_ATTR_X_CONFID,
+ SDP_ATTR_GROUP,
+ SDP_ATTR_MID,
+ SDP_ATTR_SOURCE_FILTER,
+ SDP_ATTR_RTCP_UNICAST,
+ SDP_ATTR_MAXPRATE,
+ SDP_ATTR_SQN,
+ SDP_ATTR_CDSC,
+ SDP_ATTR_CPAR,
+ SDP_ATTR_SPRTMAP,
+ SDP_ATTR_SDESCRIPTIONS, /* version 9 sdescriptions */
+ SDP_ATTR_LABEL,
+ SDP_ATTR_FRAMERATE,
+ SDP_ATTR_ICE_CANDIDATE,
+ SDP_ATTR_ICE_UFRAG,
+ SDP_ATTR_ICE_PWD,
+ SDP_ATTR_ICE_LITE,
+ SDP_ATTR_RTCP_MUX,
+ SDP_ATTR_DTLS_FINGERPRINT,
+ SDP_ATTR_MAXPTIME,
+ SDP_ATTR_RTCP_FB, /* RFC 4585 */
+ SDP_ATTR_SETUP,
+ SDP_ATTR_CONNECTION,
+ SDP_ATTR_EXTMAP, /* RFC 5285 */
+ SDP_ATTR_IDENTITY,
+ SDP_ATTR_MSID,
+ SDP_ATTR_MSID_SEMANTIC,
+ SDP_ATTR_BUNDLE_ONLY,
+ SDP_ATTR_END_OF_CANDIDATES,
+ SDP_ATTR_ICE_OPTIONS,
+ SDP_ATTR_SSRC,
+ SDP_ATTR_IMAGEATTR,
+ SDP_ATTR_SIMULCAST,
+ SDP_ATTR_RID,
+ SDP_ATTR_DTLS_MESSAGE,
+ SDP_MAX_ATTR_TYPES,
+ SDP_ATTR_INVALID
+} sdp_attr_e;
+
+typedef enum {
+ SDP_SETUP_NOT_FOUND = -1,
+ SDP_SETUP_ACTIVE = 0,
+ SDP_SETUP_PASSIVE,
+ SDP_SETUP_ACTPASS,
+ SDP_SETUP_HOLDCONN,
+ SDP_MAX_SETUP,
+ SDP_SETUP_UNKNOWN
+} sdp_setup_type_e;
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/ccsdp_rtcp_fb.h b/media/webrtc/signaling/src/sdp/sipcc/ccsdp_rtcp_fb.h
new file mode 100644
index 000000000..5518521ba
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/ccsdp_rtcp_fb.h
@@ -0,0 +1,63 @@
+/* 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 __CCSDP_RTCP_FB_H__
+#define __CCSDP_RTCP_FB_H__
+
+/* a=rtcp-fb enumerations */
+
+typedef enum {
+ SDP_RTCP_FB_ANY = -1,
+ SDP_RTCP_FB_ACK = 0,
+ SDP_RTCP_FB_CCM,
+ SDP_RTCP_FB_NACK,
+ SDP_RTCP_FB_TRR_INT,
+ // from https://www.ietf.org/archive/id/draft-alvestrand-rmcat-remb-03.txt
+ SDP_RTCP_FB_REMB,
+ SDP_MAX_RTCP_FB,
+ SDP_RTCP_FB_UNKNOWN
+} sdp_rtcp_fb_type_e;
+
+typedef enum {
+ SDP_RTCP_FB_NACK_NOT_FOUND = -1,
+ SDP_RTCP_FB_NACK_BASIC = 0,
+ SDP_RTCP_FB_NACK_SLI,
+ SDP_RTCP_FB_NACK_PLI,
+ SDP_RTCP_FB_NACK_RPSI,
+ SDP_RTCP_FB_NACK_APP,
+ SDP_RTCP_FB_NACK_RAI,
+ SDP_RTCP_FB_NACK_TLLEI,
+ SDP_RTCP_FB_NACK_PSLEI,
+ SDP_RTCP_FB_NACK_ECN,
+ SDP_MAX_RTCP_FB_NACK,
+ SDP_RTCP_FB_NACK_UNKNOWN
+} sdp_rtcp_fb_nack_type_e;
+
+typedef enum {
+ SDP_RTCP_FB_ACK_NOT_FOUND = -1,
+ SDP_RTCP_FB_ACK_RPSI = 0,
+ SDP_RTCP_FB_ACK_APP,
+ SDP_MAX_RTCP_FB_ACK,
+ SDP_RTCP_FB_ACK_UNKNOWN
+} sdp_rtcp_fb_ack_type_e;
+
+// Codec Control Messages - defined by RFC 5104
+typedef enum {
+ SDP_RTCP_FB_CCM_NOT_FOUND = -1,
+ SDP_RTCP_FB_CCM_FIR = 0,
+ SDP_RTCP_FB_CCM_TMMBR,
+ SDP_RTCP_FB_CCM_TSTR,
+ SDP_RTCP_FB_CCM_VBCM,
+ SDP_MAX_RTCP_FB_CCM,
+ SDP_RTCP_FB_CCM_UNKNOWN
+} sdp_rtcp_fb_ccm_type_e;
+
+#ifdef __cplusplus
+static_assert(SDP_MAX_RTCP_FB_NACK +
+ SDP_MAX_RTCP_FB_ACK +
+ SDP_MAX_RTCP_FB_CCM < 32,
+ "rtcp-fb Bitmap is larger than 32 bits");
+#endif
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_darwin_types.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_darwin_types.h
new file mode 100644
index 000000000..97a2644b5
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_darwin_types.h
@@ -0,0 +1,68 @@
+/* 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 _CPR_DARWIN_TYPES_H_
+#define _CPR_DARWIN_TYPES_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stddef.h>
+#include "inttypes.h"
+
+
+/**
+ * @typedef boolean
+ *
+ * Define boolean as an unsigned byte
+ *
+ * @note There are differences within TNP header files
+ * @li curses.h: bool => char
+ * @li types.h: boolean_t => enum
+ * @li dki_lock.h: bool_t => int
+ */
+typedef uint8_t boolean;
+
+/*
+ * Define min/max
+ * defined in param.h
+ *
+ * The GNU versions of the MAX and MIN macros do two things better than
+ * the old versions:
+ * 1. they are more optimal as they only evaluate a & b once by creating a
+ * a variable of each type on the local stack.
+ * 2. they fix potential errors due to side-effects where a and b were
+ * evaluated twice, i.e. MIN(i++,j++)
+ *
+ * @note b could be cast to a's type, to help with usage where the code
+ * compares signed and unsigned types.
+ */
+#ifndef MIN
+#ifdef __GNUC__
+#define MIN(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
+#else
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#endif
+
+#ifndef MAX
+#ifdef __GNUC__
+#define MAX(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
+#else
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#endif
+
+/**
+ * Define TRUE/FALSE
+ * defined in several header files
+ */
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_linux_types.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_linux_types.h
new file mode 100644
index 000000000..78f05f413
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_linux_types.h
@@ -0,0 +1,82 @@
+/* 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 _CPR_LINUX_TYPES_H_
+#define _CPR_LINUX_TYPES_H_
+
+#include "sys/types.h"
+#include "stddef.h"
+#include "inttypes.h"
+
+/**
+ * @typedef boolean
+ *
+ * Define boolean as an unsigned byte
+ *
+ * @note There are differences within TNP header files
+ * @li curses.h: bool => char
+ * @li types.h: boolean_t => enum
+ * @li dki_lock.h: bool_t => int
+ */
+typedef uint8_t boolean;
+
+/*
+ * Define size_t
+ * defined in numerous header files
+ */
+/* DONE (sys/types.h => unsigned int) */
+
+/*
+ * Define ssize_t
+ */
+/* DONE (sys/types.h => int) */
+
+/*
+ * Define MIN/MAX
+ * defined in param.h
+ *
+ * The GNU versions of the MAX and MIN macros do two things better than
+ * the old versions:
+ * 1. they are more optimal as they only evaluate a & b once by creating a
+ * a variable of each type on the local stack.
+ * 2. they fix potential errors due to side-effects where a and b were
+ * evaluated twice, i.e. MIN(i++,j++)
+ *
+ * @note b could be cast to a's type, to help with usage where the code
+ * compares signed and unsigned types.
+ */
+#ifndef MIN
+#ifdef __GNUC__
+#define MIN(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
+#else
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#endif
+
+#ifndef MAX
+#ifdef __GNUC__
+#define MAX(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
+#else
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#endif
+
+/**
+ * Define TRUE/FALSE
+ * defined in several header files
+ */
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * Define offsetof
+ */
+/* DONE (stddef.h) */
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_string.c b/media/webrtc/signaling/src/sdp/sipcc/cpr_string.c
new file mode 100644
index 000000000..c210c3971
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_string.c
@@ -0,0 +1,272 @@
+/* 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/. */
+
+#include <stdarg.h>
+
+#include "mozilla/Assertions.h"
+#include "cpr_types.h"
+#include "cpr_string.h"
+#include "cpr_strings.h"
+
+/* From cpr_stdlib.h */
+#include "mozilla/mozalloc.h"
+
+#define cpr_malloc(a) moz_xmalloc(a)
+#define cpr_calloc(a, b) moz_xcalloc(a, b)
+#define cpr_realloc(a, b) moz_xrealloc(a, b)
+#define cpr_free(a) free(a)
+
+
+/**
+ * sstrncpy
+ *
+ * This is Cisco's *safe* version of strncpy. The string will always
+ * be NUL terminated (which is not ANSI compliant).
+ *
+ * Parameters: s1 - first string
+ * s2 - second string
+ * max - maximum length in octets to concat.
+ *
+ * Return: Pointer to the *end* of the string
+ *
+ * Remarks: Modified to be explicitly safe for all inputs.
+ * Also return the number of characters copied excluding the
+ * NUL terminator vs. the original string s1. This simplifies
+ * code where sstrncat functions follow.
+ */
+unsigned long
+sstrncpy (char *dst, const char *src, unsigned long max)
+{
+ unsigned long cnt = 0;
+
+ if (dst == NULL) {
+ return 0;
+ }
+
+ if (src) {
+ while ((max-- > 1) && (*src)) {
+ *dst = *src;
+ dst++;
+ src++;
+ cnt++;
+ }
+ }
+
+#if defined(CPR_SSTRNCPY_PAD)
+ /*
+ * To be equivalent to the TI compiler version
+ * v2.01, SSTRNCPY_PAD needs to be defined
+ */
+ while (max-- > 1) {
+ *dst = '\0';
+ dst++;
+ }
+#endif
+ *dst = '\0';
+
+ return cnt;
+}
+
+/**
+ * sstrncat
+ *
+ * This is Cisco's *safe* version of strncat. The string will always
+ * be NUL terminated (which is not ANSI compliant).
+ *
+ * Parameters: s1 - first string
+ * s2 - second string
+ * max - maximum length in octets to concatenate
+ *
+ * Return: Pointer to the *end* of the string
+ *
+ * Remarks: Modified to be explicitly safe for all inputs.
+ * Also return the end vs. the beginning of the string s1
+ * which is useful for multiple sstrncat calls.
+ */
+char *
+sstrncat (char *s1, const char *s2, unsigned long max)
+{
+ if (s1 == NULL)
+ return (char *) NULL;
+
+ while (*s1)
+ s1++;
+
+ if (s2) {
+ while ((max-- > 1) && (*s2)) {
+ *s1 = *s2;
+ s1++;
+ s2++;
+ }
+ }
+ *s1 = '\0';
+
+ return s1;
+}
+
+/*
+ * flex_string
+ */
+
+/*
+ * flex_string_init
+ *
+ * Not thread-safe
+ */
+void flex_string_init(flex_string *fs) {
+ fs->buffer_length = FLEX_STRING_CHUNK_SIZE;
+ fs->string_length = 0;
+ fs->buffer = cpr_malloc(fs->buffer_length);
+ fs->buffer[0] = '\0';
+}
+
+/*
+ * flex_string_free
+ *
+ * Not thread-safe
+ */
+void flex_string_free(flex_string *fs) {
+ fs->buffer_length = 0;
+ fs->string_length = 0;
+ cpr_free(fs->buffer);
+ fs->buffer = NULL;
+}
+
+/* For sanity check before alloc */
+#define FLEX_STRING_MAX_SIZE (10 * 1024 * 1024) /* 10MB */
+
+/*
+ * flex_string_check_alloc
+ *
+ * Allocate enough chunks to hold the new minimum size.
+ *
+ * Not thread-safe
+ */
+void flex_string_check_alloc(flex_string *fs, size_t new_min_length) {
+ if (new_min_length > fs->buffer_length) {
+ /* Oversize, allocate more */
+
+ /* Sanity check on allocation size */
+ if (new_min_length > FLEX_STRING_MAX_SIZE) {
+ MOZ_CRASH();
+ }
+
+ /* Alloc to nearest chunk */
+ fs->buffer_length = (((new_min_length - 1) / FLEX_STRING_CHUNK_SIZE) + 1) * FLEX_STRING_CHUNK_SIZE;
+
+ fs->buffer = cpr_realloc(fs->buffer, fs->buffer_length);
+ }
+}
+
+/*
+ * flex_string_append
+ *
+ * Not thread-safe
+ */
+void flex_string_append(flex_string *fs, const char *more) {
+ fs->string_length += strlen(more);
+
+ flex_string_check_alloc(fs, fs->string_length + 1);
+
+ sstrncat(fs->buffer, more, fs->buffer_length - strlen(fs->buffer));
+}
+
+/*
+ * va_copy is part of the C99 spec but MSVC doesn't have it.
+ */
+#ifndef va_copy
+#define va_copy(d,s) ((d) = (s))
+#endif
+
+/*
+ * flex_string_vsprintf
+ *
+ * Not thread-safe
+ */
+void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap) {
+ va_list ap;
+ int vsnprintf_result;
+
+ va_copy(ap, original_ap);
+ vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
+ va_end(ap);
+
+ /* Special case just for Windows where vsnprintf is broken
+ and returns -1 if buffer too large unless you size it 0. */
+ if (vsnprintf_result < 0) {
+ va_copy(ap, original_ap);
+ vsnprintf_result = vsnprintf(NULL, 0, format, ap);
+ va_end(ap);
+ }
+
+ if (fs->string_length + vsnprintf_result >= fs->buffer_length) {
+ /* Buffer overflow, resize */
+ flex_string_check_alloc(fs, fs->string_length + vsnprintf_result + 1);
+
+ /* Try again with new buffer */
+ va_copy(ap, original_ap);
+ vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
+ va_end(ap);
+ MOZ_ASSERT(vsnprintf_result > 0 &&
+ (size_t)vsnprintf_result < (fs->buffer_length - fs->string_length));
+ }
+
+ if (vsnprintf_result > 0) {
+ fs->string_length += vsnprintf_result;
+ }
+}
+
+/*
+ * flex_string_sprintf
+ *
+ * Not thread-safe
+ */
+void flex_string_sprintf(flex_string *fs, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ flex_string_vsprintf(fs, format, ap);
+ va_end(ap);
+}
+
+
+
+/* From cpr_linux_string.c */
+/**
+ * cpr_strdup
+ *
+ * @brief The CPR wrapper for strdup
+
+ * The cpr_strdup shall return a pointer to a new string, which is a duplicate
+ * of the string pointed to by "str" argument. A null pointer is returned if the
+ * new string cannot be created.
+ *
+ * @param[in] str - The string that needs to be duplicated
+ *
+ * @return The duplicated string or NULL in case of no memory
+ *
+ */
+char *
+cpr_strdup (const char *str)
+{
+ char *dup;
+ size_t len;
+
+ if (!str) {
+ return (char *) NULL;
+ }
+
+ len = strlen(str);
+ if (len == 0) {
+ return (char *) NULL;
+ }
+ len++;
+
+ dup = cpr_malloc(len * sizeof(char));
+ if (!dup) {
+ return (char *) NULL;
+ }
+ (void) memcpy(dup, str, len);
+ return dup;
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_string.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_string.h
new file mode 100644
index 000000000..de6b1cc8a
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_string.h
@@ -0,0 +1,139 @@
+/* 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 _CPR_STRING_H_
+#define _CPR_STRING_H_
+
+#include <stdarg.h>
+
+#include "cpr_types.h"
+#include "cpr_strings.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * sstrncpy
+ *
+ * @brief The CPR wrapper for strncpy
+ *
+ * This is Cisco's *safe* version of strncpy. The string will always
+ * be NUL terminated (which is not ANSI compliant).
+ *
+ * @param[in] dst - The destination string
+ * @param[in] src - The source
+ * @param[in] max - maximum length in octets to concatenate
+ *
+ * @return Pointer to the @b end of the string
+ *
+ * @note Modified to be explicitly safe for all inputs.
+ * Also return the number of characters copied excluding the
+ * NUL terminator vs. the original string s1. This simplifies
+ * code where sstrncat functions follow.
+ */
+unsigned long
+sstrncpy(char *dst, const char *src, unsigned long max);
+
+
+/**
+ * sstrncat
+ *
+ * @brief The CPR wrapper for strncat
+ *
+ * This is Cisco's *safe* version of strncat. The string will always
+ * be NUL terminated (which is not ANSI compliant).
+ *
+ * @param[in] s1 - first string
+ * @param[in] s2 - second string
+ * @param[in] max - maximum length in octets to concatenate
+ *
+ * @return Pointer to the @b end of the string
+ *
+ * @note Modified to be explicitly safe for all inputs.
+ * Also return the end vs. the beginning of the string s1
+ * which is useful for multiple sstrncat calls.
+ */
+char *
+sstrncat(char *s1, const char *s2, unsigned long max);
+
+
+/*
+ * flex_string
+ */
+#define FLEX_STRING_CHUNK_SIZE 256
+
+typedef struct {
+ char *buffer;
+ size_t buffer_length;
+ size_t string_length;
+} flex_string;
+
+/*
+ * flex_string_init
+ *
+ * Not thread-safe
+ */
+void flex_string_init(flex_string *fs);
+
+/*
+ * flex_string_free
+ *
+ * Not thread-safe
+ */
+void flex_string_free(flex_string *fs);
+
+/*
+ * flex_string_check_alloc
+ *
+ * Allocate enough chunks to hold the new minimum size.
+ *
+ * Not thread-safe
+ */
+void flex_string_check_alloc(flex_string *fs, size_t new_min_length);
+
+/*
+ * flex_string_append
+ *
+ * Not thread-safe
+ */
+void flex_string_append(flex_string *fs, const char *more);
+
+/*
+ * flex_string_sprintf
+ *
+ * Not thread-safe
+ */
+void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap);
+
+/*
+ * flex_string_sprintf
+ *
+ * Not thread-safe
+ */
+void flex_string_sprintf(flex_string *fs, const char *format, ...);
+
+
+/* From cpr_linux_string.h */
+/* cpr_strdup
+ *
+ * @brief The CPR wrapper for strdup
+
+ * The cpr_strdup shall return a pointer to a new string, which is a duplicate
+ * of the string pointed to by "str" argument. A null pointer is returned if the
+ * new string cannot be created.
+ *
+ * @param[in] str - The string that needs to be duplicated
+ *
+ * @return The duplicated string or NULL in case of no memory
+ *
+ */
+char *
+cpr_strdup(const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_strings.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_strings.h
new file mode 100644
index 000000000..2d18d4638
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_strings.h
@@ -0,0 +1,22 @@
+/* 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 _CPR_STRINGS_H_
+#define _CPR_STRINGS_H_
+
+#include "cpr_types.h"
+
+#include <string.h>
+
+#if defined(_MSC_VER)
+#define cpr_strcasecmp _stricmp
+#define cpr_strncasecmp _strnicmp
+#else // _MSC_VER
+
+#define cpr_strcasecmp strcasecmp
+#define cpr_strncasecmp strncasecmp
+
+#endif // _MSC_VER
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_types.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_types.h
new file mode 100644
index 000000000..808067e61
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_types.h
@@ -0,0 +1,126 @@
+/* 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 _CPR_TYPES_H_
+#define _CPR_TYPES_H_
+
+#if defined SIP_OS_LINUX
+#include "cpr_linux_types.h"
+#elif defined SIP_OS_WINDOWS
+#include "cpr_win_types.h"
+#elif defined SIP_OS_OSX
+#include "cpr_darwin_types.h"
+#else
+//lol
+//#error "Unsupported platform"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * CPR Return Codes
+ */
+typedef enum
+{
+ CPR_SUCCESS,
+ CPR_FAILURE
+} cpr_status_e;
+typedef cpr_status_e cprRC_t;
+
+/*
+ * IPv4 address structure
+ */
+typedef uint32_t cpr_in_addr_t;
+
+struct in_addr_s
+{
+#ifdef s_addr
+ /* can occur with Windows winsock.h */
+ union {
+ struct {
+ unsigned char s_b1, s_b2, sb_b3, s_b4;
+ } S_un_b;
+ cpr_in_addr_t S_addr;
+ } S_un;
+#else
+ cpr_in_addr_t s_addr;
+#endif
+};
+
+/*
+ * IPv6 address structure
+ */
+typedef struct
+{
+ union
+ {
+ uint8_t base8[16];
+ uint16_t base16[8];
+ uint32_t base32[4];
+ } addr;
+} cpr_in6_addr_t;
+
+#ifndef s6_addr
+#define s6_addr addr.base8
+#endif
+#ifndef s6_addr16
+#define s6_addr16 addr.base16
+#endif
+#ifndef s6_addr32
+#define s6_addr32 addr.base32
+#endif
+
+typedef enum
+{
+ CPR_IP_ADDR_INVALID=0,
+ CPR_IP_ADDR_IPV4,
+ CPR_IP_ADDR_IPV6
+} cpr_ip_type;
+
+typedef enum
+{
+ CPR_IP_MODE_IPV4 = 0,
+ CPR_IP_MODE_IPV6,
+ CPR_IP_MODE_DUAL
+}
+cpr_ip_mode_e;
+/*
+ * IP address structure
+ */
+typedef struct
+{
+ cpr_ip_type type;
+ union
+ {
+ cpr_in_addr_t ip4;
+ cpr_in6_addr_t ip6;
+ } u;
+} cpr_ip_addr_t;
+
+extern const cpr_ip_addr_t ip_addr_invalid;
+
+#define MAX_IPADDR_STR_LEN 48
+
+
+#define CPR_IP_ADDR_INIT(a) a.type = CPR_IP_ADDR_INVALID;
+
+/*
+ * !!! NOTE !!!
+ *
+ * The strings of type string_t are actually very special blocks
+ * of memory that have a "hidden" header block immediately preceding
+ * the pointer. You MUST use the functions in string_lib.c to
+ * create, manipulate, destroy, copy, or otherwise work with these
+ * strings.
+ */
+
+typedef const char *string_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/media/webrtc/signaling/src/sdp/sipcc/cpr_win_types.h b/media/webrtc/signaling/src/sdp/sipcc/cpr_win_types.h
new file mode 100644
index 000000000..c4dfa0b72
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/cpr_win_types.h
@@ -0,0 +1,71 @@
+/* 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 _CPR_WIN_TYPES_H_
+#define _CPR_WIN_TYPES_H_
+
+#include <sys/types.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#ifdef SIPCC_BUILD
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windef.h>
+#endif
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Define POSIX types
+ * [u]int[8,16,32,64]_t
+ */
+#include <stdint.h>
+
+/*
+ * Define boolean
+ * in windef.h: BOOL => int
+ */
+typedef uint8_t boolean;
+
+/*
+ * Define ssize_t if required. The MinGW W32API already defines ssize_t
+ * in <sys/types.h> (protected by _SSIZE_T_) so this will only apply to
+ * Microsoft SDK.
+ *
+ * NOTE: size_t should already be declared by both the MinGW and Microsoft
+ * SDKs.
+ */
+#ifndef _SSIZE_T_
+#define _SSIZE_T_
+typedef int ssize_t;
+#endif
+
+/*
+ * Define pid_t.
+ */
+typedef int pid_t;
+
+/*
+ * Define min/max
+ * defined in windef.h as lowercase
+ */
+#ifndef MIN
+#define MIN min
+#endif
+
+#ifndef MAX
+#define MAX max
+#endif
+
+/*
+ * Define NULL
+ * defined in numerous header files
+ */
+/* DONE defined in windef.h */
+
+#endif // _CPR_WIN_TYPES_H_
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp.h b/media/webrtc/signaling/src/sdp/sipcc/sdp.h
new file mode 100644
index 000000000..9bd2ce132
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp.h
@@ -0,0 +1,1794 @@
+/* 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 _SIPCC_SDP_H_
+#define _SIPCC_SDP_H_
+
+#include "sdp_os_defs.h"
+#include "ccsdp.h"
+
+/* SDP Defines */
+
+/* The following defines are used to indicate params that are specified
+ * as the choose parameter or parameters that are invalid. These can
+ * be used where the value required is really a uint16_t, but is represented
+ * by an int32_t.
+ */
+#define SDP_CHOOSE_PARAM (-1)
+#define SDP_SESSION_LEVEL 0xFFFF
+
+#define UNKNOWN_CRYPTO_SUITE "UNKNOWN_CRYPTO_SUITE"
+#define AES_CM_128_HMAC_SHA1_32 "AES_CM_128_HMAC_SHA1_32"
+#define AES_CM_128_HMAC_SHA1_80 "AES_CM_128_HMAC_SHA1_80"
+#define F8_128_HMAC_SHA1_80 "F8_128_HMAC_SHA1_80"
+
+/* Pulled in from rtp_defs.h. */
+#define GET_DYN_PAYLOAD_TYPE_VALUE(a) ((a & 0XFF00) ? ((a & 0XFF00) >> 8) : a)
+#define SET_PAYLOAD_TYPE_WITH_DYNAMIC(a,b) ((a << 8) | b)
+
+/*
+ * SDP_SRTP_MAX_KEY_SIZE_BYTES
+ * Maximum size for a SRTP Master Key in bytes.
+ */
+#define SDP_SRTP_MAX_KEY_SIZE_BYTES 16
+/*
+ * SDP_SRTP_MAX_SALT_SIZE_BYTES
+ * Maximum size for a SRTP Master Salt in bytes.
+ */
+#define SDP_SRTP_MAX_SALT_SIZE_BYTES 14
+/*
+ * SDP_SRTP_MAX_MKI_SIZE_BYTES
+ * Maximum size for a SRTP Master Key Index in bytes.
+ */
+#define SDP_SRTP_MAX_MKI_SIZE_BYTES 4
+
+/* Max number of characters for Lifetime */
+#define SDP_SRTP_MAX_LIFETIME_BYTES 16
+
+#define SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN 0
+#define SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN 0
+
+/* Max number of fmtp redundant encodings */
+#define SDP_FMTP_MAX_REDUNDANT_ENCODINGS 128
+
+/*
+ * SRTP_CONTEXT_SET_*
+ * Set a SRTP Context field flag
+ */
+#define SDP_SRTP_ENCRYPT_MASK 0x00000001
+#define SDP_SRTP_AUTHENTICATE_MASK 0x00000002
+#define SDP_SRTCP_ENCRYPT_MASK 0x00000004
+#define SDP_SRTCP_SSRC_MASK 0x20000000
+#define SDP_SRTCP_ROC_MASK 0x10000000
+#define SDP_SRTCP_KDR_MASK 0x08000000
+#define SDP_SRTCP_KEY_MASK 0x80000000
+#define SDP_SRTCP_SALT_MASK 0x40000000
+
+#define SDP_SRTP_CONTEXT_SET_SSRC(cw) ((cw) |= SDP_SRTCP_SSRC_MASK)
+#define SDP_SRTP_CONTEXT_SET_ROC(cw) ((cw) |= SDP_SRTCP_ROC_MASK)
+#define SDP_SRTP_CONTEXT_SET_KDR(cw) ((cw) |= SDP_SRTCP_KDR_MASK)
+#define SDP_SRTP_CONTEXT_SET_MASTER_KEY(cw) ((cw) |= SDP_SRTCP_KEY_MASK)
+#define SDP_SRTP_CONTEXT_SET_MASTER_SALT(cw) ((cw) |= SDP_SRTCP_SALT_MASK)
+#define SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE(cw) \
+ ((cw) |= (SDP_SRTP_ENCRYPT_MASK | SDP_SRTP_AUTHENTICATE_MASK | \
+ SDP_SRTCP_ENCRYPT_MASK))
+#define SDP_SRTP_CONTEXT_RESET_SSRC(cw) ((cw) &= ~(SDP_SRTCP_SSRC_MASK))
+#define SDP_SRTP_CONTEXT_RESET_ROC(cw) ((cw) &= ~(SDP_SRTCP_ROC_MASK))
+#define SDP_SRTP_CONTEXT_RESET_KDR(cw) ((cw) &= ~(SDP_SRTCP_KDR_MASK))
+#define SDP_CONTEXT_RESET_MASTER_KEY(cw) ((cw) &= ~(SDP_SRTCP_KEY_MASK))
+#define SDP_CONTEXT_RESET_MASTER_SALT(cw) ((cw) &= ~(SDP_SRTCP_SALT_MASK))
+#define SDP_EXTMAP_AUDIO_LEVEL "urn:ietf:params:rtp-hdrext:ssrc-audio-level"
+
+/* SDP Enum Types */
+typedef enum {
+ SDP_DEBUG_TRACE,
+ SDP_DEBUG_WARNINGS,
+ SDP_DEBUG_ERRORS,
+ SDP_MAX_DEBUG_TYPES
+} sdp_debug_e;
+
+typedef enum {
+ SDP_CHOOSE_CONN_ADDR,
+ SDP_CHOOSE_PORTNUM,
+ SDP_MAX_CHOOSE_PARAMS
+} sdp_choose_param_e;
+
+
+/* Token Lines - these must be in the same order they should
+ * appear in an SDP.
+ */
+typedef enum {
+ SDP_TOKEN_V = 0,
+ SDP_TOKEN_O,
+ SDP_TOKEN_S,
+ SDP_TOKEN_I,
+ SDP_TOKEN_U,
+ SDP_TOKEN_E,
+ SDP_TOKEN_P,
+ SDP_TOKEN_C,
+ SDP_TOKEN_B,
+ SDP_TOKEN_T,
+ SDP_TOKEN_R,
+ SDP_TOKEN_Z,
+ SDP_TOKEN_K,
+ SDP_TOKEN_A,
+ SDP_TOKEN_M,
+ SDP_MAX_TOKENS
+} sdp_token_e;
+
+/* Media Types */
+typedef enum {
+ SDP_MEDIA_AUDIO = 0,
+ SDP_MEDIA_VIDEO,
+ SDP_MEDIA_APPLICATION,
+ SDP_MEDIA_DATA,
+ SDP_MEDIA_CONTROL,
+ SDP_MEDIA_NAS_RADIUS,
+ SDP_MEDIA_NAS_TACACS,
+ SDP_MEDIA_NAS_DIAMETER,
+ SDP_MEDIA_NAS_L2TP,
+ SDP_MEDIA_NAS_LOGIN,
+ SDP_MEDIA_NAS_NONE,
+ SDP_MEDIA_TEXT,
+ SDP_MEDIA_IMAGE,
+ SDP_MAX_MEDIA_TYPES,
+ SDP_MEDIA_UNSUPPORTED,
+ SDP_MEDIA_INVALID
+} sdp_media_e;
+
+
+/* Connection Network Type */
+typedef enum {
+ SDP_NT_INTERNET = 0, /* 0 -> IP - In SDP "IN" is defined */
+ /* to mean "Internet" */
+ SDP_NT_ATM, /* 1 -> ATM */
+ SDP_NT_FR, /* 2 -> FRAME RELAY */
+ SDP_NT_LOCAL, /* 3 -> local */
+ SDP_MAX_NETWORK_TYPES,
+ SDP_NT_UNSUPPORTED,
+ SDP_NT_INVALID
+} sdp_nettype_e;
+
+
+/* Address Type */
+typedef enum {
+ SDP_AT_IP4 = 0, /* 0 -> IP Version 4 (IP4) */
+ SDP_AT_IP6, /* 1 -> IP Version 6 (IP6) */
+ SDP_AT_NSAP, /* 2 -> 20 byte NSAP address */
+ SDP_AT_EPN, /* 3 -> 32 bytes of endpoint name */
+ SDP_AT_E164, /* 4 -> 15 digit decimal number addr */
+ SDP_AT_GWID, /* 5 -> Private gw id. ASCII string */
+ SDP_MAX_ADDR_TYPES,
+ SDP_AT_UNSUPPORTED,
+ SDP_AT_FQDN,
+ SDP_AT_INVALID
+} sdp_addrtype_e;
+
+
+/* Transport Types */
+
+#define SDP_MAX_PROFILES 3
+
+typedef enum {
+ SDP_TRANSPORT_RTPAVP = 0,
+ SDP_TRANSPORT_UDP,
+ SDP_TRANSPORT_UDPTL,
+ SDP_TRANSPORT_CES10,
+ SDP_TRANSPORT_LOCAL,
+ SDP_TRANSPORT_AAL2_ITU,
+ SDP_TRANSPORT_AAL2_ATMF,
+ SDP_TRANSPORT_AAL2_CUSTOM,
+ SDP_TRANSPORT_AAL1AVP,
+ SDP_TRANSPORT_UDPSPRT,
+ SDP_TRANSPORT_RTPSAVP,
+ SDP_TRANSPORT_TCP,
+ SDP_TRANSPORT_RTPSAVPF,
+ SDP_TRANSPORT_DTLSSCTP,
+ SDP_TRANSPORT_RTPAVPF,
+ SDP_TRANSPORT_UDPTLSRTPSAVP,
+ SDP_TRANSPORT_UDPTLSRTPSAVPF,
+ SDP_TRANSPORT_TCPTLSRTPSAVP,
+ SDP_TRANSPORT_TCPTLSRTPSAVPF,
+ SDP_MAX_TRANSPORT_TYPES,
+ SDP_TRANSPORT_UNSUPPORTED,
+ SDP_TRANSPORT_INVALID
+} sdp_transport_e;
+
+
+/* Encryption KeyType */
+typedef enum {
+ SDP_ENCRYPT_CLEAR, /* 0 -> Key given in the clear */
+ SDP_ENCRYPT_BASE64, /* 1 -> Base64 encoded key */
+ SDP_ENCRYPT_URI, /* 2 -> Ptr to URI */
+ SDP_ENCRYPT_PROMPT, /* 3 -> No key included, prompt user */
+ SDP_MAX_ENCRYPT_TYPES,
+ SDP_ENCRYPT_UNSUPPORTED,
+ SDP_ENCRYPT_INVALID
+} sdp_encrypt_type_e;
+
+
+/* Known string payload types */
+typedef enum {
+ SDP_PAYLOAD_T38,
+ SDP_PAYLOAD_XTMR,
+ SDP_PAYLOAD_T120,
+ SDP_MAX_STRING_PAYLOAD_TYPES,
+ SDP_PAYLOAD_UNSUPPORTED,
+ SDP_PAYLOAD_INVALID
+} sdp_payload_e;
+
+
+/* Payload type indicator */
+typedef enum {
+ SDP_PAYLOAD_NUMERIC,
+ SDP_PAYLOAD_ENUM
+} sdp_payload_ind_e;
+
+
+/* Image payload types */
+typedef enum {
+ SDP_PORT_NUM_ONLY, /* <port> or '$' */
+ SDP_PORT_NUM_COUNT, /* <port>/<number of ports> */
+ SDP_PORT_VPI_VCI, /* <vpi>/<vci> */
+ SDP_PORT_VCCI, /* <vcci> */
+ SDP_PORT_NUM_VPI_VCI, /* <port>/<vpi>/<vci> */
+ SDP_PORT_VCCI_CID, /* <vcci>/<cid> or '$'/'$' */
+ SDP_PORT_NUM_VPI_VCI_CID, /* <port>/<vpi>/<vci>/<cid> */
+ SDP_MAX_PORT_FORMAT_TYPES,
+ SDP_PORT_FORMAT_INVALID
+} sdp_port_format_e;
+
+
+/* Fmtp attribute format Types */
+typedef enum {
+ SDP_FMTP_NTE,
+ SDP_FMTP_CODEC_INFO,
+ SDP_FMTP_MODE,
+ SDP_FMTP_DATACHANNEL,
+ SDP_FMTP_UNKNOWN_TYPE,
+ SDP_FMTP_MAX_TYPE
+} sdp_fmtp_format_type_e;
+
+
+/* T.38 Rate Mgmt Types */
+typedef enum {
+ SDP_T38_LOCAL_TCF,
+ SDP_T38_TRANSFERRED_TCF,
+ SDP_T38_UNKNOWN_RATE,
+ SDP_T38_MAX_RATES
+} sdp_t38_ratemgmt_e;
+
+
+/* T.38 udp EC Types */
+typedef enum {
+ SDP_T38_UDP_REDUNDANCY,
+ SDP_T38_UDP_FEC,
+ SDP_T38_UDPEC_UNKNOWN,
+ SDP_T38_MAX_UDPEC
+} sdp_t38_udpec_e;
+
+/* Bitmaps for manipulating sdp_direction_e */
+typedef enum {
+ SDP_DIRECTION_FLAG_SEND=0x01,
+ SDP_DIRECTION_FLAG_RECV=0x02
+} sdp_direction_flag_e;
+
+/* Media flow direction */
+typedef enum {
+ SDP_DIRECTION_INACTIVE = 0,
+ SDP_DIRECTION_SENDONLY = SDP_DIRECTION_FLAG_SEND,
+ SDP_DIRECTION_RECVONLY = SDP_DIRECTION_FLAG_RECV,
+ SDP_DIRECTION_SENDRECV = SDP_DIRECTION_FLAG_SEND | SDP_DIRECTION_FLAG_RECV,
+ SDP_MAX_QOS_DIRECTIONS
+} sdp_direction_e;
+
+#define SDP_DIRECTION_PRINT(arg) \
+ (((sdp_direction_e)(arg)) == SDP_DIRECTION_INACTIVE ? "SDP_DIRECTION_INACTIVE " : \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDONLY ? "SDP_DIRECTION_SENDONLY": \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_RECVONLY ? "SDP_DIRECTION_RECVONLY ": \
+ ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDRECV ? " SDP_DIRECTION_SENDRECV": "SDP_MAX_QOS_DIRECTIONS")
+
+
+/* QOS Strength tag */
+typedef enum {
+ SDP_QOS_STRENGTH_OPT,
+ SDP_QOS_STRENGTH_MAND,
+ SDP_QOS_STRENGTH_SUCC,
+ SDP_QOS_STRENGTH_FAIL,
+ SDP_QOS_STRENGTH_NONE,
+ SDP_MAX_QOS_STRENGTH,
+ SDP_QOS_STRENGTH_UNKNOWN
+} sdp_qos_strength_e;
+
+
+/* QOS direction */
+typedef enum {
+ SDP_QOS_DIR_SEND,
+ SDP_QOS_DIR_RECV,
+ SDP_QOS_DIR_SENDRECV,
+ SDP_QOS_DIR_NONE,
+ SDP_MAX_QOS_DIR,
+ SDP_QOS_DIR_UNKNOWN
+} sdp_qos_dir_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_QOS_LOCAL,
+ SDP_QOS_REMOTE,
+ SDP_QOS_E2E,
+ SDP_MAX_QOS_STATUS_TYPES,
+ SDP_QOS_STATUS_TYPE_UNKNOWN
+} sdp_qos_status_types_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_CURR_QOS_TYPE,
+ SDP_CURR_UNKNOWN_TYPE,
+ SDP_MAX_CURR_TYPES
+} sdp_curr_type_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_DES_QOS_TYPE,
+ SDP_DES_UNKNOWN_TYPE,
+ SDP_MAX_DES_TYPES
+} sdp_des_type_e;
+
+/* QoS Status types */
+typedef enum {
+ SDP_CONF_QOS_TYPE,
+ SDP_CONF_UNKNOWN_TYPE,
+ SDP_MAX_CONF_TYPES
+} sdp_conf_type_e;
+
+
+/* Named event range result values. */
+typedef enum {
+ SDP_NO_MATCH,
+ SDP_PARTIAL_MATCH,
+ SDP_FULL_MATCH
+} sdp_ne_res_e;
+
+/* Fmtp attribute parameters for audio/video codec information */
+typedef enum {
+
+ /* mainly for audio codecs */
+ SDP_ANNEX_A, /* 0 */
+ SDP_ANNEX_B,
+ SDP_BITRATE,
+
+ /* for video codecs */
+ SDP_QCIF,
+ SDP_CIF,
+ SDP_MAXBR,
+ SDP_SQCIF,
+ SDP_CIF4,
+ SDP_CIF16,
+ SDP_CUSTOM,
+ SDP_PAR,
+ SDP_CPCF,
+ SDP_BPP,
+ SDP_HRD,
+ SDP_PROFILE,
+ SDP_LEVEL,
+ SDP_INTERLACE,
+
+ /* H.264 related */
+ SDP_PROFILE_LEVEL_ID, /* 17 */
+ SDP_PARAMETER_SETS,
+ SDP_PACKETIZATION_MODE,
+ SDP_INTERLEAVING_DEPTH,
+ SDP_DEINT_BUF_REQ,
+ SDP_MAX_DON_DIFF,
+ SDP_INIT_BUF_TIME,
+
+ SDP_MAX_MBPS,
+ SDP_MAX_FS,
+ SDP_MAX_CPB,
+ SDP_MAX_DPB,
+ SDP_MAX_BR,
+ SDP_REDUNDANT_PIC_CAP,
+ SDP_DEINT_BUF_CAP,
+ SDP_MAX_RCMD_NALU_SIZE,
+
+ SDP_PARAMETER_ADD,
+
+ /* Annexes - begin */
+ /* Some require special handling as they don't have token=token format*/
+ SDP_ANNEX_D,
+ SDP_ANNEX_F,
+ SDP_ANNEX_I,
+ SDP_ANNEX_J,
+ SDP_ANNEX_T,
+
+ /* These annexes have token=token format */
+ SDP_ANNEX_K,
+ SDP_ANNEX_N,
+ SDP_ANNEX_P,
+
+ SDP_MODE,
+ SDP_LEVEL_ASYMMETRY_ALLOWED,
+ SDP_MAX_AVERAGE_BIT_RATE,
+ SDP_USED_TX,
+ SDP_STEREO,
+ SDP_USE_IN_BAND_FEC,
+ SDP_MAX_CODED_AUDIO_BW,
+ SDP_CBR,
+ SDP_MAX_FR,
+ SDP_MAX_PLAYBACK_RATE,
+ SDP_MAX_FMTP_PARAM,
+ SDP_FMTP_PARAM_UNKNOWN
+} sdp_fmtp_codec_param_e;
+
+/* Fmtp attribute parameters values for
+ fmtp attribute parameters which convey codec
+ information */
+
+typedef enum {
+ SDP_YES,
+ SDP_NO,
+ SDP_MAX_FMTP_PARAM_VAL,
+ SDP_FMTP_PARAM_UNKNOWN_VAL
+} sdp_fmtp_codec_param_val_e;
+
+/* silenceSupp suppPref */
+typedef enum {
+ SDP_SILENCESUPP_PREF_STANDARD,
+ SDP_SILENCESUPP_PREF_CUSTOM,
+ SDP_SILENCESUPP_PREF_NULL, /* "-" */
+ SDP_MAX_SILENCESUPP_PREF,
+ SDP_SILENCESUPP_PREF_UNKNOWN
+} sdp_silencesupp_pref_e;
+
+/* silenceSupp sidUse */
+typedef enum {
+ SDP_SILENCESUPP_SIDUSE_NOSID,
+ SDP_SILENCESUPP_SIDUSE_FIXED,
+ SDP_SILENCESUPP_SIDUSE_SAMPLED,
+ SDP_SILENCESUPP_SIDUSE_NULL, /* "-" */
+ SDP_MAX_SILENCESUPP_SIDUSE,
+ SDP_SILENCESUPP_SIDUSE_UNKNOWN
+} sdp_silencesupp_siduse_e;
+
+typedef enum {
+ SDP_MEDIADIR_ROLE_PASSIVE,
+ SDP_MEDIADIR_ROLE_ACTIVE,
+ SDP_MEDIADIR_ROLE_BOTH,
+ SDP_MEDIADIR_ROLE_REUSE,
+ SDP_MEDIADIR_ROLE_UNKNOWN,
+ SDP_MAX_MEDIADIR_ROLES,
+ SDP_MEDIADIR_ROLE_UNSUPPORTED,
+ SDP_MEDIADIR_ROLE_INVALID
+} sdp_mediadir_role_e;
+
+typedef enum {
+ SDP_GROUP_ATTR_FID,
+ SDP_GROUP_ATTR_LS,
+ SDP_GROUP_ATTR_ANAT,
+ SDP_GROUP_ATTR_BUNDLE,
+ SDP_MAX_GROUP_ATTR_VAL,
+ SDP_GROUP_ATTR_UNSUPPORTED
+} sdp_group_attr_e;
+
+typedef enum {
+ SDP_SRC_FILTER_INCL,
+ SDP_SRC_FILTER_EXCL,
+ SDP_MAX_FILTER_MODE,
+ SDP_FILTER_MODE_NOT_PRESENT
+} sdp_src_filter_mode_e;
+
+typedef enum {
+ SDP_RTCP_UNICAST_MODE_REFLECTION,
+ SDP_RTCP_UNICAST_MODE_RSI,
+ SDP_RTCP_MAX_UNICAST_MODE,
+ SDP_RTCP_UNICAST_MODE_NOT_PRESENT
+} sdp_rtcp_unicast_mode_e;
+
+typedef enum {
+ SDP_CONNECTION_NOT_FOUND = -1,
+ SDP_CONNECTION_NEW = 0,
+ SDP_CONNECTION_EXISTING,
+ SDP_MAX_CONNECTION,
+ SDP_CONNECTION_UNKNOWN
+} sdp_connection_type_e;
+
+/*
+ * sdp_srtp_fec_order_t
+ * This type defines the order in which to perform FEC
+ * (Forward Error Correction) and SRTP Encryption/Authentication.
+ */
+typedef enum sdp_srtp_fec_order_t_ {
+ SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */
+ SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */
+ SDP_SRTP_FEC_SPLIT /* upon sending perform SRTP Encryption,
+ * then FEC, the SRTP Authentication */
+} sdp_srtp_fec_order_t;
+
+
+/*
+ * sdp_srtp_crypto_suite_t
+ * Enumeration of the crypto suites supported for MGCP SRTP
+ * package.
+ */
+typedef enum sdp_srtp_crypto_suite_t_ {
+ SDP_SRTP_UNKNOWN_CRYPTO_SUITE = 0,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80,
+ SDP_SRTP_F8_128_HMAC_SHA1_80,
+ SDP_SRTP_MAX_NUM_CRYPTO_SUITES
+} sdp_srtp_crypto_suite_t;
+
+/*
+ * SDP SRTP crypto suite definition parameters
+ *
+ * SDP_SRTP_<crypto_suite>_KEY_BYTES
+ * The size of a master key for <crypto_suite> in bytes.
+ *
+ * SDP_SRTP_<crypto_suite>_SALT_BYTES
+ * The size of a master salt for <crypto_suite> in bytes.
+ */
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES 16
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES 14
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES 16
+#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES 14
+#define SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES 16
+#define SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES 14
+
+/* SDP Defines */
+
+#define SDP_MAX_LONG_STRING_LEN 4096 /* Max len for long SDP strings */
+#define SDP_MAX_STRING_LEN 256 /* Max len for SDP string */
+#define SDP_MAX_SHORT_STRING_LEN 12 /* Max len for a short SDP string */
+#define SDP_MAX_PAYLOAD_TYPES 23 /* Max payload types in m= line */
+#define SDP_TOKEN_LEN 2 /* Len of <token>= */
+#define SDP_CURRENT_VERSION 0 /* Current default SDP version */
+#define SDP_MAX_PORT_PARAMS 4 /* Max m= port params - x/x/x/x */
+#define SDP_MIN_DYNAMIC_PAYLOAD 96 /* Min dynamic payload */
+#define SDP_MAX_DYNAMIC_PAYLOAD 127 /* Max dynamic payload */
+#define SDP_MIN_CIF_VALUE 1 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */
+#define SDP_MAX_CIF_VALUE 32 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */
+#define SDP_MAX_SRC_ADDR_LIST 1 /* Max source addrs for which filter applies */
+
+
+#define SDP_DEFAULT_PACKETIZATION_MODE_VALUE 0 /* max packetization mode for H.264 */
+#define SDP_MAX_PACKETIZATION_MODE_VALUE 2 /* max packetization mode for H.264 */
+#define SDP_INVALID_PACKETIZATION_MODE_VALUE 255
+
+#define SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* max level asymmetry allowed value for H.264 */
+#define SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE 0 /* default level asymmetry allowed value for H.264 */
+#define SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE 2 /* invalid value for level-asymmetry-allowed param for H.264 */
+
+
+/* Max number of stream ids that can be grouped together */
+#define SDP_MAX_MEDIA_STREAMS 32
+
+#define SDP_UNSUPPORTED "Unsupported"
+#define SDP_MAX_LINE_LEN 256 /* Max len for SDP Line */
+
+#define SDP_MAX_PROFILE_VALUE 10
+#define SDP_MAX_LEVEL_VALUE 100
+#define SDP_MIN_PROFILE_LEVEL_VALUE 0
+#define SDP_MAX_TTL_VALUE 255
+#define SDP_MIN_MCAST_ADDR_HI_BIT_VAL 224
+#define SDP_MAX_MCAST_ADDR_HI_BIT_VAL 239
+
+/* SDP Enum Types */
+
+typedef enum {
+ SDP_ERR_INVALID_CONF_PTR,
+ SDP_ERR_INVALID_SDP_PTR,
+ SDP_ERR_INTERNAL,
+ SDP_MAX_ERR_TYPES
+} sdp_errmsg_e;
+
+/* SDP Structure Definitions */
+
+/* String names of varios tokens */
+typedef struct {
+ char *name;
+ uint8_t strlen;
+} sdp_namearray_t;
+
+/* c= line info */
+typedef struct {
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char conn_addr[SDP_MAX_STRING_LEN+1];
+ tinybool is_multicast;
+ uint16_t ttl;
+ uint16_t num_of_addresses;
+} sdp_conn_t;
+
+/* t= line info */
+typedef struct sdp_timespec {
+ char start_time[SDP_MAX_STRING_LEN+1];
+ char stop_time[SDP_MAX_STRING_LEN+1];
+ struct sdp_timespec *next_p;
+} sdp_timespec_t;
+
+
+/* k= line info */
+typedef struct sdp_encryptspec {
+ sdp_encrypt_type_e encrypt_type;
+ char encrypt_key[SDP_MAX_STRING_LEN+1];
+} sdp_encryptspec_t;
+
+
+/* FMTP attribute deals with named events in the range of 0-255 as
+ * defined in RFC 2833 */
+#define SDP_MIN_NE_VALUE 0
+#define SDP_MAX_NE_VALUES 256
+#define SDP_NE_BITS_PER_WORD ( sizeof(uint32_t) * 8 )
+#define SDP_NE_NUM_BMAP_WORDS ((SDP_MAX_NE_VALUES + SDP_NE_BITS_PER_WORD - 1)/SDP_NE_BITS_PER_WORD )
+#define SDP_NE_BIT_0 ( 0x00000001 )
+#define SDP_NE_ALL_BITS ( 0xFFFFFFFF )
+
+#define SDP_DEINT_BUF_REQ_FLAG 0x1
+#define SDP_INIT_BUF_TIME_FLAG 0x2
+#define SDP_MAX_RCMD_NALU_SIZE_FLAG 0x4
+#define SDP_DEINT_BUF_CAP_FLAG 0x8
+
+#define SDP_FMTP_UNUSED 0xFFFF
+
+typedef struct sdp_fmtp {
+ uint16_t payload_num;
+ uint32_t maxval; /* maxval optimizes bmap search */
+ uint32_t bmap[ SDP_NE_NUM_BMAP_WORDS ];
+ sdp_fmtp_format_type_e fmtp_format; /* Gives the format type
+ for FMTP attribute*/
+ tinybool annexb_required;
+ tinybool annexa_required;
+
+ tinybool annexa;
+ tinybool annexb;
+ uint32_t bitrate;
+ uint32_t mode;
+
+ /* some OPUS specific fmtp params */
+ uint32_t maxplaybackrate;
+ uint32_t maxaveragebitrate;
+ uint16_t usedtx;
+ uint16_t stereo;
+ uint16_t useinbandfec;
+ char maxcodedaudiobandwidth[SDP_MAX_STRING_LEN+1];
+ uint16_t cbr;
+
+ /* BEGIN - All Video related FMTP parameters */
+ uint16_t qcif;
+ uint16_t cif;
+ uint16_t maxbr;
+ uint16_t sqcif;
+ uint16_t cif4;
+ uint16_t cif16;
+
+ uint16_t custom_x;
+ uint16_t custom_y;
+ uint16_t custom_mpi;
+ /* CUSTOM=360,240,4 implies X-AXIS=360, Y-AXIS=240; MPI=4 */
+ uint16_t par_width;
+ uint16_t par_height;
+ /* PAR=12:11 implies par_width=12, par_height=11 */
+
+ /* CPCF should be a float. IOS does not support float and so it is uint16_t */
+ /* For portable stack, CPCF should be defined as float and the parsing should
+ * be modified accordingly */
+ uint16_t cpcf;
+ uint16_t bpp;
+ uint16_t hrd;
+
+ int16_t profile;
+ int16_t level;
+ tinybool is_interlace;
+
+ /* some more H.264 specific fmtp params */
+ char profile_level_id[SDP_MAX_STRING_LEN+1];
+ char parameter_sets[SDP_MAX_STRING_LEN+1];
+ uint16_t packetization_mode;
+ uint16_t level_asymmetry_allowed;
+ uint16_t interleaving_depth;
+ uint32_t deint_buf_req;
+ uint32_t max_don_diff;
+ uint32_t init_buf_time;
+
+ uint32_t max_mbps;
+ uint32_t max_fs;
+ uint32_t max_fr;
+ uint32_t max_cpb;
+ uint32_t max_dpb;
+ uint32_t max_br;
+ tinybool redundant_pic_cap;
+ uint32_t deint_buf_cap;
+ uint32_t max_rcmd_nalu_size;
+ uint16_t parameter_add;
+
+ tinybool annex_d;
+
+ tinybool annex_f;
+ tinybool annex_i;
+ tinybool annex_j;
+ tinybool annex_t;
+
+ /* H.263 codec requires annex K,N and P to have values */
+ uint16_t annex_k_val;
+ uint16_t annex_n_val;
+
+ /* RFC 5109 Section 4.2 for specifying redundant encodings */
+ uint8_t redundant_encodings[SDP_FMTP_MAX_REDUNDANT_ENCODINGS];
+
+ /* RFC 2833 Section 3.9 (4733) for specifying support DTMF tones:
+ The list of values consists of comma-separated elements, which
+ can be either a single decimal number or two decimal numbers
+ separated by a hyphen (dash), where the second number is larger
+ than the first. No whitespace is allowed between numbers or
+ hyphens. The list does not have to be sorted.
+ */
+ char dtmf_tones[SDP_MAX_STRING_LEN+1];
+
+ /* Annex P can take one or more values in the range 1-4 . e.g P=1,3 */
+ uint16_t annex_p_val_picture_resize; /* 1 = four; 2 = sixteenth */
+ uint16_t annex_p_val_warp; /* 3 = half; 4=sixteenth */
+
+ uint8_t flag;
+
+ /* END - All Video related FMTP parameters */
+
+} sdp_fmtp_t;
+
+/* a=sctpmap line used for Datachannels */
+typedef struct sdp_sctpmap {
+ uint16_t port;
+ uint32_t streams; /* Num streams per Datachannel */
+ char protocol[SDP_MAX_STRING_LEN+1];
+} sdp_sctpmap_t;
+
+#define SDP_MAX_MSID_LEN 64
+
+typedef struct sdp_msid {
+ char identifier[SDP_MAX_MSID_LEN+1];
+ char appdata[SDP_MAX_MSID_LEN+1];
+} sdp_msid_t;
+
+/* a=qos|secure|X-pc-qos|X-qos info */
+typedef struct sdp_qos {
+ sdp_qos_strength_e strength;
+ sdp_qos_dir_e direction;
+ tinybool confirm;
+ sdp_qos_status_types_e status_type;
+} sdp_qos_t;
+
+/* a=curr:qos status_type direction */
+typedef struct sdp_curr {
+ sdp_curr_type_e type;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_curr_t;
+
+/* a=des:qos strength status_type direction */
+typedef struct sdp_des {
+ sdp_des_type_e type;
+ sdp_qos_strength_e strength;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_des_t;
+
+/* a=conf:qos status_type direction */
+typedef struct sdp_conf {
+ sdp_conf_type_e type;
+ sdp_qos_status_types_e status_type;
+ sdp_qos_dir_e direction;
+} sdp_conf_t;
+
+
+/* a=rtpmap or a=sprtmap info */
+typedef struct sdp_transport_map {
+ uint16_t payload_num;
+ char encname[SDP_MAX_STRING_LEN+1];
+ uint32_t clockrate;
+ uint16_t num_chan;
+} sdp_transport_map_t;
+
+
+/* a=rtr info */
+typedef struct sdp_rtr {
+ tinybool confirm;
+} sdp_rtr_t;
+
+/* a=subnet info */
+typedef struct sdp_subnet {
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char addr[SDP_MAX_STRING_LEN+1];
+ int32_t prefix;
+} sdp_subnet_t;
+
+
+/* a=X-pc-codec info */
+typedef struct sdp_pccodec {
+ uint16_t num_payloads;
+ ushort payload_type[SDP_MAX_PAYLOAD_TYPES];
+} sdp_pccodec_t;
+
+/* a=direction info */
+typedef struct sdp_comediadir {
+ sdp_mediadir_role_e role;
+ tinybool conn_info_present;
+ sdp_conn_t conn_info;
+ uint32_t src_port;
+} sdp_comediadir_t;
+
+
+
+/* a=silenceSupp info */
+typedef struct sdp_silencesupp {
+ tinybool enabled;
+ tinybool timer_null;
+ uint16_t timer;
+ sdp_silencesupp_pref_e pref;
+ sdp_silencesupp_siduse_e siduse;
+ tinybool fxnslevel_null;
+ uint8_t fxnslevel;
+} sdp_silencesupp_t;
+
+
+/*
+ * a=mptime info */
+/* Note that an interval value of zero corresponds to
+ * the "-" syntax on the a= line.
+ */
+typedef struct sdp_mptime {
+ uint16_t num_intervals;
+ ushort intervals[SDP_MAX_PAYLOAD_TYPES];
+} sdp_mptime_t;
+
+/*
+ * a=X-sidin:<val>, a=X-sidout:< val> and a=X-confid: <val>
+ * Stream Id,ConfID related attributes to be used for audio/video conferencing
+ *
+*/
+
+typedef struct sdp_stream_data {
+ char x_sidin[SDP_MAX_STRING_LEN+1];
+ char x_sidout[SDP_MAX_STRING_LEN+1];
+ char x_confid[SDP_MAX_STRING_LEN+1];
+ sdp_group_attr_e group_attr; /* FID or LS */
+ uint16_t num_group_id;
+ char * group_ids[SDP_MAX_MEDIA_STREAMS];
+} sdp_stream_data_t;
+
+typedef struct sdp_msid_semantic {
+ char semantic[SDP_MAX_STRING_LEN+1];
+ char * msids[SDP_MAX_MEDIA_STREAMS];
+} sdp_msid_semantic_t;
+
+/*
+ * a=source-filter:<filter-mode> <filter-spec>
+ * <filter-spec> = <nettype> <addrtype> <dest-addr> <src_addr><src_addr>...
+ * One or more source addresses to apply filter, for one or more connection
+ * address in unicast/multicast environments
+ */
+typedef struct sdp_source_filter {
+ sdp_src_filter_mode_e mode;
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char dest_addr[SDP_MAX_STRING_LEN+1];
+ uint16_t num_src_addr;
+ char src_list[SDP_MAX_SRC_ADDR_LIST+1][SDP_MAX_STRING_LEN+1];
+} sdp_source_filter_t;
+
+/*
+ * a=rtcp-fb:<payload-type> <feedback-type> [<feedback-parameters>]
+ * Defines RTCP feedback parameters
+ */
+#define SDP_ALL_PAYLOADS 0xFFFF
+typedef struct sdp_fmtp_fb {
+ uint16_t payload_num; /* can be SDP_ALL_PAYLOADS */
+ sdp_rtcp_fb_type_e feedback_type;
+ union {
+ sdp_rtcp_fb_ack_type_e ack;
+ sdp_rtcp_fb_ccm_type_e ccm;
+ sdp_rtcp_fb_nack_type_e nack;
+ uint32_t trr_int;
+ } param;
+ char extra[SDP_MAX_STRING_LEN + 1]; /* Holds any trailing information that
+ cannot be represented by preceding
+ fields. */
+} sdp_fmtp_fb_t;
+
+typedef struct sdp_rtcp {
+ sdp_nettype_e nettype;
+ sdp_addrtype_e addrtype;
+ char addr[SDP_MAX_STRING_LEN+1];
+ uint16_t port;
+} sdp_rtcp_t;
+
+/*
+ * b=<bw-modifier>:<val>
+ *
+*/
+typedef struct sdp_bw_data {
+ struct sdp_bw_data *next_p;
+ sdp_bw_modifier_e bw_modifier;
+ int bw_val;
+} sdp_bw_data_t;
+
+/*
+ * This structure houses a linked list of sdp_bw_data_t instances. Each
+ * sdp_bw_data_t instance represents one b= line.
+ */
+typedef struct sdp_bw {
+ uint16_t bw_data_count;
+ sdp_bw_data_t *bw_data_list;
+} sdp_bw_t;
+
+/* Media lines for AAL2 may have more than one transport type defined
+ * each with its own payload type list. These are referred to as
+ * profile types instead of transport types. This structure is used
+ * to handle these multiple profile types. Note: One additional profile
+ * field is needed because of the way parsing is done. This is not an
+ * error. */
+typedef struct sdp_media_profiles {
+ uint16_t num_profiles;
+ sdp_transport_e profile[SDP_MAX_PROFILES+1];
+ uint16_t num_payloads[SDP_MAX_PROFILES];
+ sdp_payload_ind_e payload_indicator[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
+ uint16_t payload_type[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
+} sdp_media_profiles_t;
+/*
+ * a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
+ *
+ */
+typedef struct sdp_extmap {
+ uint16_t id;
+ sdp_direction_e media_direction;
+ tinybool media_direction_specified;
+ char uri[SDP_MAX_STRING_LEN+1];
+ char extension_attributes[SDP_MAX_STRING_LEN+1];
+} sdp_extmap_t;
+
+typedef struct sdp_ssrc {
+ uint32_t ssrc;
+ char attribute[SDP_MAX_STRING_LEN + 1];
+} sdp_ssrc_t;
+
+/*
+ * sdp_srtp_crypto_context_t
+ * This type is used to hold cryptographic context information.
+ *
+ */
+typedef struct sdp_srtp_crypto_context_t_ {
+ int32_t tag;
+ unsigned long selection_flags;
+ sdp_srtp_crypto_suite_t suite;
+ unsigned char master_key[SDP_SRTP_MAX_KEY_SIZE_BYTES];
+ unsigned char master_salt[SDP_SRTP_MAX_SALT_SIZE_BYTES];
+ unsigned char master_key_size_bytes;
+ unsigned char master_salt_size_bytes;
+ unsigned long ssrc; /* not used */
+ unsigned long roc; /* not used */
+ unsigned long kdr; /* not used */
+ unsigned short seq; /* not used */
+ sdp_srtp_fec_order_t fec_order; /* not used */
+ unsigned char master_key_lifetime[SDP_SRTP_MAX_LIFETIME_BYTES];
+ unsigned char mki[SDP_SRTP_MAX_MKI_SIZE_BYTES];
+ uint16_t mki_size_bytes;
+ char* session_parameters;
+} sdp_srtp_crypto_context_t;
+
+
+/* m= line info and associated attribute list */
+/* Note: Most of the port parameter values are 16-bit values. We set
+ * the type to int32_t so we can return either a 16-bit value or the
+ * choose value. */
+typedef struct sdp_mca {
+ sdp_media_e media;
+ sdp_conn_t conn;
+ sdp_transport_e transport;
+ sdp_port_format_e port_format;
+ int32_t port;
+ int32_t sctpport;
+ int32_t num_ports;
+ int32_t vpi;
+ uint32_t vci; /* VCI needs to be 32-bit */
+ int32_t vcci;
+ int32_t cid;
+ uint16_t num_payloads;
+ sdp_payload_ind_e payload_indicator[SDP_MAX_PAYLOAD_TYPES];
+ uint16_t payload_type[SDP_MAX_PAYLOAD_TYPES];
+ sdp_media_profiles_t *media_profiles_p;
+ tinybool sessinfo_found;
+ sdp_encryptspec_t encrypt;
+ sdp_bw_t bw;
+ sdp_attr_e media_direction; /* Either INACTIVE, SENDONLY,
+ RECVONLY, or SENDRECV */
+ uint32_t mid;
+ uint32_t line_number;
+ struct sdp_attr *media_attrs_p;
+ struct sdp_mca *next_p;
+} sdp_mca_t;
+
+
+/* generic a= line info */
+typedef struct sdp_attr {
+ sdp_attr_e type;
+ uint32_t line_number;
+ union {
+ tinybool boolean_val;
+ uint32_t u32_val;
+ char string_val[SDP_MAX_STRING_LEN+1];
+ char *stringp;
+ char ice_attr[SDP_MAX_STRING_LEN+1];
+ sdp_fmtp_t fmtp;
+ sdp_sctpmap_t sctpmap;
+ sdp_msid_t msid;
+ sdp_qos_t qos;
+ sdp_curr_t curr;
+ sdp_des_t des;
+ sdp_conf_t conf;
+ sdp_transport_map_t transport_map; /* A rtpmap or sprtmap */
+ sdp_subnet_t subnet;
+ sdp_t38_ratemgmt_e t38ratemgmt;
+ sdp_t38_udpec_e t38udpec;
+ sdp_pccodec_t pccodec;
+ sdp_silencesupp_t silencesupp;
+ sdp_mca_t *cap_p; /* A X-CAP or CDSC attribute */
+ sdp_rtr_t rtr;
+ sdp_comediadir_t comediadir;
+ sdp_srtp_crypto_context_t srtp_context;
+ sdp_mptime_t mptime;
+ sdp_stream_data_t stream_data;
+ sdp_msid_semantic_t msid_semantic;
+ char unknown[SDP_MAX_STRING_LEN+1];
+ sdp_source_filter_t source_filter;
+ sdp_fmtp_fb_t rtcp_fb;
+ sdp_rtcp_t rtcp;
+ sdp_setup_type_e setup;
+ sdp_connection_type_e connection;
+ sdp_extmap_t extmap;
+ sdp_ssrc_t ssrc;
+ } attr;
+ struct sdp_attr *next_p;
+} sdp_attr_t;
+typedef struct sdp_srtp_crypto_suite_list_ {
+ sdp_srtp_crypto_suite_t crypto_suite_val;
+ char * crypto_suite_str;
+ unsigned char key_size_bytes;
+ unsigned char salt_size_bytes;
+} sdp_srtp_crypto_suite_list;
+
+typedef void (*sdp_parse_error_handler)(void *context,
+ uint32_t line,
+ const char *message);
+
+/* Application configuration options */
+typedef struct sdp_conf_options {
+ tinybool debug_flag[SDP_MAX_DEBUG_TYPES];
+ tinybool version_reqd;
+ tinybool owner_reqd;
+ tinybool session_name_reqd;
+ tinybool timespec_reqd;
+ tinybool media_supported[SDP_MAX_MEDIA_TYPES];
+ tinybool nettype_supported[SDP_MAX_NETWORK_TYPES];
+ tinybool addrtype_supported[SDP_MAX_ADDR_TYPES];
+ tinybool transport_supported[SDP_MAX_TRANSPORT_TYPES];
+ tinybool allow_choose[SDP_MAX_CHOOSE_PARAMS];
+ /* Statistics counts */
+ uint32_t num_builds;
+ uint32_t num_parses;
+ uint32_t num_not_sdp_desc;
+ uint32_t num_invalid_token_order;
+ uint32_t num_invalid_param;
+ uint32_t num_no_resource;
+ struct sdp_conf_options *next_p;
+ sdp_parse_error_handler error_handler;
+ void *error_handler_context;
+} sdp_conf_options_t;
+
+
+/* Session level SDP info with pointers to media line info. */
+/* Elements here that can only be one of are included directly. Elements */
+/* that can be more than one are pointers. */
+typedef struct {
+ sdp_conf_options_t *conf_p;
+ tinybool debug_flag[SDP_MAX_DEBUG_TYPES];
+ char debug_str[SDP_MAX_STRING_LEN+1];
+ uint32_t debug_id;
+ int32_t version; /* version is really a uint16_t */
+ char owner_name[SDP_MAX_STRING_LEN+1];
+ char owner_sessid[SDP_MAX_STRING_LEN+1];
+ char owner_version[SDP_MAX_STRING_LEN+1];
+ sdp_nettype_e owner_network_type;
+ sdp_addrtype_e owner_addr_type;
+ char owner_addr[SDP_MAX_STRING_LEN+1];
+ char sessname[SDP_MAX_STRING_LEN+1];
+ tinybool sessinfo_found;
+ tinybool uri_found;
+ sdp_conn_t default_conn;
+ sdp_timespec_t *timespec_p;
+ sdp_encryptspec_t encrypt;
+ sdp_bw_t bw;
+ sdp_attr_t *sess_attrs_p;
+
+ /* Info to help with building capability attributes. */
+ uint16_t cur_cap_num;
+ sdp_mca_t *cur_cap_p;
+ /* Info to help parsing X-cpar attrs. */
+ uint16_t cap_valid;
+ uint16_t last_cap_inst;
+ /* Info to help building X-cpar/cpar attrs. */
+ sdp_attr_e last_cap_type;
+
+ /* Facilitates reporting line number for SDP errors */
+ uint32_t parse_line;
+
+ /* MCA - Media, connection, and attributes */
+ sdp_mca_t *mca_p;
+ ushort mca_count;
+} sdp_t;
+
+
+/* Token processing table. */
+typedef struct {
+ char *name;
+ sdp_result_e (*parse_func)(sdp_t *sdp_p, uint16_t level, const char *ptr);
+ sdp_result_e (*build_func)(sdp_t *sdp_p, uint16_t level, flex_string *fs);
+} sdp_tokenarray_t;
+
+/* Attribute processing table. */
+typedef struct {
+ char *name;
+ uint16_t strlen;
+ sdp_result_e (*parse_func)(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+ sdp_result_e (*build_func)(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+} sdp_attrarray_t;
+
+
+/* Prototypes */
+
+/* sdp_config.c */
+extern sdp_conf_options_t *sdp_init_config(void);
+extern void sdp_free_config(sdp_conf_options_t *config_p);
+extern void sdp_appl_debug(sdp_conf_options_t *config_p, sdp_debug_e debug_type,
+ tinybool debug_flag);
+extern void sdp_require_version(sdp_conf_options_t *config_p, tinybool version_required);
+extern void sdp_require_owner(sdp_conf_options_t *config_p, tinybool owner_required);
+extern void sdp_require_session_name(sdp_conf_options_t *config_p,
+ tinybool sess_name_required);
+extern void sdp_require_timespec(sdp_conf_options_t *config_p, tinybool timespec_required);
+extern void sdp_media_supported(sdp_conf_options_t *config_p, sdp_media_e media_type,
+ tinybool media_supported);
+extern void sdp_nettype_supported(sdp_conf_options_t *config_p, sdp_nettype_e nettype,
+ tinybool nettype_supported);
+extern void sdp_addrtype_supported(sdp_conf_options_t *config_p, sdp_addrtype_e addrtype,
+ tinybool addrtype_supported);
+extern void sdp_transport_supported(sdp_conf_options_t *config_p, sdp_transport_e transport,
+ tinybool transport_supported);
+extern void sdp_allow_choose(sdp_conf_options_t *config_p, sdp_choose_param_e param,
+ tinybool choose_allowed);
+extern void sdp_config_set_error_handler(sdp_conf_options_t *config_p,
+ sdp_parse_error_handler handler,
+ void *context);
+
+/* sdp_main.c */
+extern sdp_t *sdp_init_description(sdp_conf_options_t *config_p);
+extern void sdp_debug(sdp_t *sdp_ptr, sdp_debug_e debug_type, tinybool debug_flag);
+extern void sdp_set_string_debug(sdp_t *sdp_ptr, const char *debug_str);
+extern sdp_result_e sdp_parse(sdp_t *sdp_ptr, const char *buf, size_t len);
+extern sdp_result_e sdp_build(sdp_t *sdp_ptr, flex_string *fs);
+extern sdp_result_e sdp_free_description(sdp_t *sdp_ptr);
+extern void sdp_parse_error(sdp_t *sdp, const char *format, ...);
+
+extern const char *sdp_get_result_name(sdp_result_e rc);
+
+
+/* sdp_access.c */
+extern tinybool sdp_version_valid(sdp_t *sdp_p);
+extern int32_t sdp_get_version(sdp_t *sdp_p);
+extern sdp_result_e sdp_set_version(sdp_t *sdp_p, int32_t version);
+
+extern tinybool sdp_owner_valid(sdp_t *sdp_p);
+extern const char *sdp_get_owner_username(sdp_t *sdp_p);
+extern const char *sdp_get_owner_sessionid(sdp_t *sdp_p);
+extern const char *sdp_get_owner_version(sdp_t *sdp_p);
+extern sdp_nettype_e sdp_get_owner_network_type(sdp_t *sdp_p);
+extern sdp_addrtype_e sdp_get_owner_address_type(sdp_t *sdp_p);
+extern const char *sdp_get_owner_address(sdp_t *sdp_p);
+extern sdp_result_e sdp_set_owner_username(sdp_t *sdp_p, const char *username);
+extern sdp_result_e sdp_set_owner_sessionid(sdp_t *sdp_p, const char *sessid);
+extern sdp_result_e sdp_set_owner_version(sdp_t *sdp_p, const char *version);
+extern sdp_result_e sdp_set_owner_network_type(sdp_t *sdp_p,
+ sdp_nettype_e network_type);
+extern sdp_result_e sdp_set_owner_address_type(sdp_t *sdp_p,
+ sdp_addrtype_e address_type);
+extern sdp_result_e sdp_set_owner_address(sdp_t *sdp_p, const char *address);
+
+extern tinybool sdp_session_name_valid(sdp_t *sdp_p);
+extern const char *sdp_get_session_name(sdp_t *sdp_p);
+extern sdp_result_e sdp_set_session_name(sdp_t *sdp_p, const char *sessname);
+
+extern tinybool sdp_timespec_valid(sdp_t *sdp_ptr);
+extern const char *sdp_get_time_start(sdp_t *sdp_ptr);
+extern const char *sdp_get_time_stop(sdp_t *sdp_ptr);
+sdp_result_e sdp_set_time_start(sdp_t *sdp_p, const char *start_time);
+sdp_result_e sdp_set_time_stop(sdp_t *sdp_p, const char *stop_time);
+
+extern tinybool sdp_encryption_valid(sdp_t *sdp_p, uint16_t level);
+extern sdp_encrypt_type_e sdp_get_encryption_method(sdp_t *sdp_p, uint16_t level);
+extern const char *sdp_get_encryption_key(sdp_t *sdp_p, uint16_t level);
+
+extern tinybool sdp_connection_valid(sdp_t *sdp_p, uint16_t level);
+extern tinybool sdp_bw_line_exists(sdp_t *sdp_p, uint16_t level, uint16_t inst_num);
+extern tinybool sdp_bandwidth_valid(sdp_t *sdp_p, uint16_t level, uint16_t inst_num);
+extern sdp_nettype_e sdp_get_conn_nettype(sdp_t *sdp_p, uint16_t level);
+extern sdp_addrtype_e sdp_get_conn_addrtype(sdp_t *sdp_p, uint16_t level);
+extern const char *sdp_get_conn_address(sdp_t *sdp_p, uint16_t level);
+
+extern tinybool sdp_is_mcast_addr (sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_mcast_ttl(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_mcast_num_of_addresses(sdp_t *sdp_p, uint16_t level);
+
+extern sdp_result_e sdp_set_conn_nettype(sdp_t *sdp_p, uint16_t level,
+ sdp_nettype_e nettype);
+extern sdp_result_e sdp_set_conn_addrtype(sdp_t *sdp_p, uint16_t level,
+ sdp_addrtype_e addrtype);
+extern sdp_result_e sdp_set_conn_address(sdp_t *sdp_p, uint16_t level,
+ const char *address);
+
+extern tinybool sdp_media_line_valid(sdp_t *sdp_p, uint16_t level);
+extern uint16_t sdp_get_num_media_lines(sdp_t *sdp_ptr);
+extern sdp_media_e sdp_get_media_type(sdp_t *sdp_p, uint16_t level);
+extern uint32_t sdp_get_media_line_number(sdp_t *sdp_p, uint16_t level);
+extern sdp_port_format_e sdp_get_media_port_format(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_media_portnum(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_media_portcount(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_media_vpi(sdp_t *sdp_p, uint16_t level);
+extern uint32_t sdp_get_media_vci(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_media_vcci(sdp_t *sdp_p, uint16_t level);
+extern int32_t sdp_get_media_cid(sdp_t *sdp_p, uint16_t level);
+extern sdp_transport_e sdp_get_media_transport(sdp_t *sdp_p, uint16_t level);
+extern uint16_t sdp_get_media_num_profiles(sdp_t *sdp_p, uint16_t level);
+extern sdp_transport_e sdp_get_media_profile(sdp_t *sdp_p, uint16_t level,
+ uint16_t profile_num);
+extern uint16_t sdp_get_media_num_payload_types(sdp_t *sdp_p, uint16_t level);
+extern uint16_t sdp_get_media_profile_num_payload_types(sdp_t *sdp_p, uint16_t level,
+ uint16_t profile_num);
+extern rtp_ptype sdp_get_known_payload_type(sdp_t *sdp_p,
+ uint16_t level,
+ uint16_t payload_type_raw);
+extern uint32_t sdp_get_media_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t payload_num, sdp_payload_ind_e *indicator);
+extern uint32_t sdp_get_media_profile_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t prof_num, uint16_t payload_num, sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_insert_media_line(sdp_t *sdp_p, uint16_t level);
+extern sdp_result_e sdp_set_media_type(sdp_t *sdp_p, uint16_t level,
+ sdp_media_e media);
+extern sdp_result_e sdp_set_media_portnum(sdp_t *sdp_p, uint16_t level,
+ int32_t portnum, int32_t sctpport);
+extern int32_t sdp_get_media_sctp_port(sdp_t *sdp_p, uint16_t level);
+extern sdp_result_e sdp_set_media_transport(sdp_t *sdp_p, uint16_t level,
+ sdp_transport_e transport);
+extern sdp_result_e sdp_add_media_profile(sdp_t *sdp_p, uint16_t level,
+ sdp_transport_e profile);
+extern sdp_result_e sdp_add_media_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t payload_type, sdp_payload_ind_e indicator);
+extern sdp_result_e sdp_add_media_profile_payload_type(sdp_t *sdp_p,
+ uint16_t level, uint16_t prof_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator);
+
+/* sdp_attr_access.c */
+extern sdp_attr_t *sdp_find_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t inst_num);
+
+extern int sdp_find_fmtp_inst(sdp_t *sdp_ptr, uint16_t level, uint16_t payload_num);
+extern sdp_result_e sdp_add_new_attr(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t *inst_num);
+extern sdp_result_e sdp_attr_num_instances(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e attr_type, uint16_t *num_attr_inst);
+extern tinybool sdp_attr_valid(sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern uint32_t sdp_attr_line_number(sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_simple_string(sdp_t *sdp_p,
+ sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_long_string(sdp_t *sdp_p,
+ sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern uint32_t sdp_attr_get_simple_u32(sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_simple_boolean(sdp_t *sdp_p,
+ sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_is_present (sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num);
+extern const char* sdp_attr_get_maxprate(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_t38_udpec_e sdp_attr_get_t38udpec(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_direction_e sdp_get_media_direction(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num);
+extern sdp_qos_strength_e sdp_attr_get_qos_strength(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_qos_status_types_e sdp_attr_get_qos_status_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_qos_dir_e sdp_attr_get_qos_direction(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern tinybool sdp_attr_get_qos_confirm(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_curr_type_e sdp_attr_get_curr_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_des_type_e sdp_attr_get_des_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_conf_type_e sdp_attr_get_conf_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num);
+extern sdp_nettype_e sdp_attr_get_subnet_nettype(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_addrtype_e sdp_attr_get_subnet_addrtype(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_subnet_addr(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_subnet_prefix(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern rtp_ptype sdp_attr_get_rtpmap_known_codec(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_rtpmap_payload_valid(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type);
+extern uint16_t sdp_attr_get_rtpmap_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_rtpmap_encname(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint32_t sdp_attr_get_rtpmap_clockrate(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint16_t sdp_attr_get_rtpmap_num_chan(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_sprtmap_payload_valid(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type);
+extern uint16_t sdp_attr_get_sprtmap_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_sprtmap_encname(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint32_t sdp_attr_get_sprtmap_clockrate(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint16_t sdp_attr_get_sprtmap_num_chan(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_fmtp_payload_valid(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type);
+extern uint16_t sdp_attr_get_fmtp_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_ne_res_e sdp_attr_fmtp_is_range_set(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint8_t low_val, uint8_t high_val);
+extern tinybool sdp_attr_fmtp_valid(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint16_t appl_maxval, uint32_t* evt_array);
+extern sdp_result_e sdp_attr_set_fmtp_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint16_t payload_num);
+extern sdp_result_e sdp_attr_get_fmtp_range(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *bmap);
+extern sdp_result_e sdp_attr_clear_fmtp_range(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint8_t low_val, uint8_t high_val);
+extern sdp_ne_res_e sdp_attr_compare_fmtp_ranges(sdp_t *src_sdp_ptr,
+ sdp_t *dst_sdp_ptr, uint16_t src_level, uint16_t dst_level,
+ uint8_t src_cap_num, uint8_t dst_cap_num, uint16_t src_inst_num,
+ uint16_t dst_inst_num);
+extern sdp_result_e sdp_attr_copy_fmtp_ranges(sdp_t *src_sdp_ptr,
+ sdp_t *dst_sdp_ptr, uint16_t src_level, uint16_t dst_level,
+ uint8_t src_cap_num, uint8_t dst_cap_num, uint16_t src_inst_num,
+ uint16_t dst_inst_num);
+extern uint32_t sdp_attr_get_fmtp_mode_for_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint32_t payload_type);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_fs (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num,
+ uint32_t max_fs);
+
+extern sdp_result_e sdp_attr_set_fmtp_max_fr (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num,
+ uint32_t max_fr);
+
+/* get routines */
+extern int32_t sdp_attr_get_fmtp_bitrate_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern int32_t sdp_attr_get_fmtp_cif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_qcif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_sqcif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_cif4 (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_cif16 (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_maxbr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t* val);
+extern sdp_result_e sdp_attr_get_fmtp_usedtx (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val);
+extern sdp_result_e sdp_attr_get_fmtp_stereo (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val);
+extern sdp_result_e sdp_attr_get_fmtp_useinbandfec (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val);
+extern char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_cbr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val);
+extern int32_t sdp_attr_get_fmtp_custom_x (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_custom_y (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_custom_mpi (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_par_width (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_par_height (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_bpp (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_hrd (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_profile (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_level (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_interlace (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_d (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_f (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_i (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_j (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern tinybool sdp_attr_get_fmtp_annex_t (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_annex_k_val (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_annex_n_val (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern int32_t sdp_attr_get_fmtp_annex_p_picture_resize (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern int32_t sdp_attr_get_fmtp_annex_p_warp (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+/* sctpmap params */
+extern uint16_t sdp_attr_get_sctpmap_port(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_result_e sdp_attr_get_sctpmap_protocol (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, char* protocol);
+extern sdp_result_e sdp_attr_get_sctpmap_streams (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t* val);
+
+extern const char *sdp_attr_get_msid_identifier(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_msid_appdata(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+/* H.264 codec specific params */
+
+extern const char *sdp_attr_get_fmtp_profile_id(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern const char *sdp_attr_get_fmtp_param_sets(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_result_e sdp_attr_get_fmtp_pack_mode (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t *val);
+
+extern sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t *val);
+
+extern sdp_result_e sdp_attr_get_fmtp_interleaving_depth (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint16_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_don_diff (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val);
+
+/* The following four H.264 parameters that require special handling as
+ * the values range from 0 - 4294967295
+ */
+extern sdp_result_e sdp_attr_get_fmtp_deint_buf_req (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_init_buf_time (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint32_t *val);
+
+
+extern sdp_result_e sdp_attr_get_fmtp_max_mbps (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_fs (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_fr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_cpb (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_dpb (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern sdp_result_e sdp_attr_get_fmtp_max_br (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val);
+extern tinybool sdp_attr_fmtp_is_redundant_pic_cap (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+extern tinybool sdp_attr_fmtp_is_parameter_add (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+extern tinybool sdp_attr_fmtp_is_annexa_set (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern tinybool sdp_attr_fmtp_is_annexb_set (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num);
+
+extern uint16_t sdp_attr_get_pccodec_num_payload_types(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint16_t sdp_attr_get_pccodec_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t payload_num);
+extern sdp_result_e sdp_attr_add_pccodec_payload_type(sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint16_t payload_type);
+extern uint16_t sdp_attr_get_xcap_first_cap_num(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern sdp_media_e sdp_attr_get_xcap_media_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern sdp_transport_e sdp_attr_get_xcap_transport_type(sdp_t *sdp_p,
+ uint16_t level, uint16_t inst_num);
+extern uint16_t sdp_attr_get_xcap_num_payload_types(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern uint16_t sdp_attr_get_xcap_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_num,
+ sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_attr_add_xcap_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator);
+extern uint16_t sdp_attr_get_cdsc_first_cap_num(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern sdp_media_e sdp_attr_get_cdsc_media_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern sdp_transport_e sdp_attr_get_cdsc_transport_type(sdp_t *sdp_p,
+ uint16_t level, uint16_t inst_num);
+extern uint16_t sdp_attr_get_cdsc_num_payload_types(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern uint16_t sdp_attr_get_cdsc_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_num,
+ sdp_payload_ind_e *indicator);
+extern sdp_result_e sdp_attr_add_cdsc_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator);
+extern tinybool sdp_media_dynamic_payload_valid (sdp_t *sdp_p, uint16_t payload_type,
+ uint16_t m_line);
+
+extern tinybool sdp_attr_get_rtr_confirm (sdp_t *, uint16_t, uint8_t, uint16_t);
+
+extern tinybool sdp_attr_get_silencesupp_enabled(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern uint16_t sdp_attr_get_silencesupp_timer(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ tinybool *null_ind);
+extern sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+extern sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+extern uint8_t sdp_attr_get_silencesupp_fxnslevel(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ tinybool *null_ind);
+extern sdp_mediadir_role_e sdp_attr_get_comediadir_role(sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num);
+
+extern uint16_t sdp_attr_get_mptime_num_intervals(
+ sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num);
+extern uint16_t sdp_attr_get_mptime_interval(
+ sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num, uint16_t interval_num);
+extern sdp_result_e sdp_attr_add_mptime_interval(
+ sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num, uint16_t interval);
+
+
+extern sdp_result_e sdp_copy_all_bw_lines(sdp_t *src_sdp_ptr, sdp_t *dst_sdp_ptr,
+ uint16_t src_level, uint16_t dst_level);
+extern sdp_bw_modifier_e sdp_get_bw_modifier(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num);
+extern const char *sdp_get_bw_modifier_name(sdp_bw_modifier_e bw_modifier);
+extern int32_t sdp_get_bw_value(sdp_t *sdp_p, uint16_t level, uint16_t inst_num);
+extern int32_t sdp_get_num_bw_lines (sdp_t *sdp_p, uint16_t level);
+
+extern sdp_result_e sdp_add_new_bw_line(sdp_t *sdp_p, uint16_t level,
+ sdp_bw_modifier_e bw_modifier, uint16_t *inst_num);
+
+extern sdp_group_attr_e sdp_get_group_attr(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern const char* sdp_attr_get_x_sidout (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+
+extern const char* sdp_attr_get_x_sidin (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern const char* sdp_attr_get_x_confid (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern uint16_t sdp_get_group_num_id(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+
+extern const char* sdp_get_group_id(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t id_num);
+
+extern int32_t sdp_get_mid_value(sdp_t *sdp_p, uint16_t level);
+extern sdp_result_e sdp_include_new_filter_src_addr(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ const char *src_addr);
+extern sdp_src_filter_mode_e sdp_get_source_filter_mode(sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num);
+extern sdp_result_e sdp_get_filter_destination_attributes(sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num,
+ sdp_nettype_e *nettype,
+ sdp_addrtype_e *addrtype,
+ char *dest_addr);
+extern int32_t sdp_get_filter_source_address_count(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num);
+extern sdp_result_e sdp_get_filter_source_address (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint16_t src_addr_id,
+ char *src_addr);
+
+extern sdp_rtcp_unicast_mode_e sdp_get_rtcp_unicast_mode(sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num);
+
+void sdp_crypto_debug(char *buffer, ulong length_bytes);
+char * sdp_debug_msg_filter(char *buffer, ulong length_bytes);
+
+extern int32_t
+sdp_attr_get_sdescriptions_tag(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern sdp_srtp_crypto_suite_t
+sdp_attr_get_sdescriptions_crypto_suite(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_key(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_salt(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern const char*
+sdp_attr_get_sdescriptions_lifetime(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern sdp_result_e
+sdp_attr_get_sdescriptions_mki(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num,
+ const char **mki_value,
+ uint16_t *mki_length);
+
+extern const char*
+sdp_attr_get_sdescriptions_session_params(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern unsigned char
+sdp_attr_get_sdescriptions_key_size(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern unsigned char
+sdp_attr_get_sdescriptions_salt_size(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+extern unsigned long
+sdp_attr_get_srtp_crypto_selection_flags(sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num);
+
+sdp_result_e
+sdp_attr_get_ice_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ char **out);
+
+sdp_result_e
+sdp_attr_get_rtcp_mux_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ tinybool *rtcp_mux);
+
+sdp_result_e
+sdp_attr_get_setup_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, sdp_setup_type_e *setup_type);
+
+sdp_result_e
+sdp_attr_get_connection_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, sdp_connection_type_e *connection_type);
+
+sdp_result_e
+sdp_attr_get_dtls_fingerprint_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ char **out);
+
+sdp_rtcp_fb_ack_type_e
+sdp_attr_get_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst);
+
+sdp_rtcp_fb_nack_type_e
+sdp_attr_get_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst);
+
+uint32_t
+sdp_attr_get_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type,
+ uint16_t inst);
+
+tinybool
+sdp_attr_get_rtcp_fb_remb_enabled(sdp_t *sdp_p, uint16_t level,
+ uint16_t payload_type);
+
+sdp_rtcp_fb_ccm_type_e
+sdp_attr_get_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst);
+
+sdp_result_e
+sdp_attr_set_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_ack_type_e type);
+
+sdp_result_e
+sdp_attr_set_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_nack_type_e);
+
+sdp_result_e
+sdp_attr_set_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type,
+ uint16_t inst, uint32_t interval);
+
+sdp_result_e
+sdp_attr_set_rtcp_fb_remb(sdp_t *sdp_p, uint16_t level, uint16_t payload_type,
+ uint16_t inst);
+
+sdp_result_e
+sdp_attr_set_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_ccm_type_e);
+const char *
+sdp_attr_get_extmap_uri(sdp_t *sdp_p, uint16_t level, uint16_t inst);
+
+uint16_t
+sdp_attr_get_extmap_id(sdp_t *sdp_p, uint16_t level, uint16_t inst);
+
+sdp_result_e
+sdp_attr_set_extmap(sdp_t *sdp_p, uint16_t level, uint16_t id, const char* uri, uint16_t inst);
+
+#endif /* _SDP_H_ */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_access.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_access.c
new file mode 100644
index 000000000..394e69bc8
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_access.c
@@ -0,0 +1,2083 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+static const char* logTag = "sdp_access";
+
+/* Pulled in from ccsip_sdp.h */
+/* Possible encoding names of static payload types*/
+#define SIPSDP_ATTR_ENCNAME_PCMU "PCMU"
+#define SIPSDP_ATTR_ENCNAME_PCMA "PCMA"
+#define SIPSDP_ATTR_ENCNAME_G729 "G729"
+#define SIPSDP_ATTR_ENCNAME_G723 "G723"
+#define SIPSDP_ATTR_ENCNAME_G726 "G726-32"
+#define SIPSDP_ATTR_ENCNAME_G728 "G728"
+#define SIPSDP_ATTR_ENCNAME_GSM "GSM"
+#define SIPSDP_ATTR_ENCNAME_CN "CN"
+#define SIPSDP_ATTR_ENCNAME_G722 "G722"
+#define SIPSDP_ATTR_ENCNAME_ILBC "iLBC"
+#define SIPSDP_ATTR_ENCNAME_H263v2 "H263-1998"
+#define SIPSDP_ATTR_ENCNAME_H264 "H264"
+#define SIPSDP_ATTR_ENCNAME_VP8 "VP8"
+#define SIPSDP_ATTR_ENCNAME_VP9 "VP9"
+#define SIPSDP_ATTR_ENCNAME_L16_256K "L16"
+#define SIPSDP_ATTR_ENCNAME_ISAC "ISAC"
+#define SIPSDP_ATTR_ENCNAME_OPUS "opus"
+#define SIPSDP_ATTR_ENCNAME_RED "red"
+#define SIPSDP_ATTR_ENCNAME_ULPFEC "ulpfec"
+#define SIPSDP_ATTR_ENCNAME_TELEPHONE_EVENT "telephone-event"
+
+/* Function: sdp_find_media_level
+ * Description: Find and return a pointer to the specified media level,
+ * if it exists.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to find.
+ * Returns: Pointer to the media level or NULL if not found.
+ */
+sdp_mca_t *sdp_find_media_level (sdp_t *sdp_p, uint16_t level)
+{
+ int i;
+ sdp_mca_t *mca_p = NULL;
+
+ if ((level >= 1) && (level <= sdp_p->mca_count)) {
+ for (i=1, mca_p = sdp_p->mca_p;
+ ((i < level) && (mca_p != NULL));
+ mca_p = mca_p->next_p, i++) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+ }
+
+ return (mca_p);
+}
+
+/* Function: sdp_version_valid
+ * Description: Returns true or false depending on whether the version
+ * set for this SDP is valid. Currently the only valid
+ * version is 0.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_version_valid (sdp_t *sdp_p)
+{
+ if (sdp_p->version == SDP_INVALID_VALUE) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_version
+ * Description: Returns the version value set for the given SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Version value.
+ */
+int32_t sdp_get_version (sdp_t *sdp_p)
+{
+ return (sdp_p->version);
+}
+
+/* Function: sdp_set_version
+ * Description: Sets the value of the version parameter for the v= version
+ * token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * version Version to set.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_version (sdp_t *sdp_p, int32_t version)
+{
+ sdp_p->version = version;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_owner_valid
+ * Description: Returns true or false depending on whether the owner
+ * token line has been defined for this SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_owner_valid (sdp_t *sdp_p)
+{
+ if ((sdp_p->owner_name[0] == '\0') ||
+ (sdp_p->owner_network_type == SDP_NT_INVALID) ||
+ (sdp_p->owner_addr_type == SDP_AT_INVALID) ||
+ (sdp_p->owner_addr[0] == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_owner_username
+ * Description: Returns a pointer to the value of the username parameter
+ * from the o= owner token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Version value.
+ */
+const char *sdp_get_owner_username (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_name);
+}
+
+/* Function: sdp_get_owner_sessionid
+ * Description: Returns the session id parameter from the o= owner token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to owner session id or NULL.
+ */
+const char *sdp_get_owner_sessionid (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_sessid);
+}
+
+/* Function: sdp_get_owner_version
+ * Description: Returns the version parameter from the o= owner token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to owner version or NULL.
+ */
+const char *sdp_get_owner_version (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_version);
+}
+
+/* Function: sdp_get_owner_network_type
+ * Description: Returns the network type parameter from the o= owner token
+ * line. If network type has not been set SDP_NT_INVALID will
+ * be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Network type or SDP_NT_INVALID.
+ */
+sdp_nettype_e sdp_get_owner_network_type (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_network_type);
+}
+
+/* Function: sdp_get_owner_address_type
+ * Description: Returns the address type parameter from the o= owner token
+ * line. If address type has not been set SDP_AT_INVALID will
+ * be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Address type or SDP_AT_INVALID.
+ */
+sdp_addrtype_e sdp_get_owner_address_type (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_addr_type);
+}
+
+/* Function: sdp_get_owner_address
+ * Description: Returns the address parameter from the o= owner token
+ * line. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to address or NULL.
+ */
+const char *sdp_get_owner_address (sdp_t *sdp_p)
+{
+ return (sdp_p->owner_addr);
+}
+
+/* Function: sdp_set_owner_username
+ * Description: Sets the value of the username parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * username Ptr to the username string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_username (sdp_t *sdp_p, const char *username)
+{
+ sstrncpy(sdp_p->owner_name, username, sizeof(sdp_p->owner_name));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_username
+ * Description: Sets the value of the session id parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * sessionid Ptr to the sessionid string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_sessionid (sdp_t *sdp_p, const char *sessionid)
+{
+ sstrncpy(sdp_p->owner_sessid, sessionid, sizeof(sdp_p->owner_sessid));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_version
+ * Description: Sets the value of the version parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * version Ptr to the version string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_version (sdp_t *sdp_p, const char *version)
+{
+ sstrncpy(sdp_p->owner_version, version, sizeof(sdp_p->owner_version));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_network_type
+ * Description: Sets the value of the network type parameter for the o= owner
+ * token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * network_type Network type for the owner line.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_network_type (sdp_t *sdp_p,
+ sdp_nettype_e network_type)
+{
+ sdp_p->owner_network_type = network_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_address_type
+ * Description: Sets the value of the address type parameter for the o= owner
+ * token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * address_type Address type for the owner line.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_address_type (sdp_t *sdp_p,
+ sdp_addrtype_e address_type)
+{
+ sdp_p->owner_addr_type = address_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_owner_address
+ * Description: Sets the value of the address parameter for the o= owner
+ * token line. The string is copied into the SDP structure
+ * so application memory will not be referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * version Ptr to the version string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_owner_address (sdp_t *sdp_p, const char *address)
+{
+ sstrncpy(sdp_p->owner_addr, address, sizeof(sdp_p->owner_addr));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_session_name_valid
+ * Description: Returns true or false depending on whether the session name
+ * s= token line has been defined for this SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_session_name_valid (sdp_t *sdp_p)
+{
+ if (sdp_p->sessname[0] == '\0') {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_session_name
+ * Description: Returns the session name parameter from the s= session
+ * name token line. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to session name or NULL.
+ */
+const char *sdp_get_session_name (sdp_t *sdp_p)
+{
+ return (sdp_p->sessname);
+}
+
+/* Function: sdp_set_session_name
+ * Description: Sets the value of the session name parameter for the s=
+ * session name token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * sessname Ptr to the session name string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_session_name (sdp_t *sdp_p, const char *sessname)
+{
+ sstrncpy(sdp_p->sessname, sessname, sizeof(sdp_p->sessname));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_timespec_valid
+ * Description: Returns true or false depending on whether the timespec t=
+ * token line has been defined for this SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_timespec_valid (sdp_t *sdp_p)
+{
+ if ((sdp_p->timespec_p == NULL) ||
+ (sdp_p->timespec_p->start_time[0] == '\0') ||
+ (sdp_p->timespec_p->stop_time[0] == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_time_start
+ * Description: Returns the start time parameter from the t= timespec token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to start time or NULL.
+ */
+const char *sdp_get_time_start (sdp_t *sdp_p)
+{
+ if (sdp_p->timespec_p != NULL) {
+ return (sdp_p->timespec_p->start_time);
+ } else {
+ return (NULL);
+ }
+}
+
+/* Function: sdp_get_time_stop
+ * Description: Returns the stop time parameter from the t= timespec token
+ * line. Because the value may be larger than 32 bits, this
+ * parameter is returned as a string, though has been verified
+ * to be numeric. Value is returned as a const ptr and so
+ * cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Ptr to stop time or NULL.
+ */
+const char *sdp_get_time_stop (sdp_t *sdp_p)
+{
+ if (sdp_p->timespec_p != NULL) {
+ return (sdp_p->timespec_p->stop_time);
+ } else {
+ return (NULL);
+ }
+}
+
+/* Function: sdp_set_time_start
+ * Description: Sets the value of the start time parameter for the t=
+ * timespec token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * start_time Ptr to the start time string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_time_start (sdp_t *sdp_p, const char *start_time)
+{
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ sdp_p->timespec_p->start_time[0] = '\0';
+ sdp_p->timespec_p->stop_time[0] = '\0';
+ }
+ sstrncpy(sdp_p->timespec_p->start_time, start_time,
+ sizeof(sdp_p->timespec_p->start_time));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_time_stop
+ * Description: Sets the value of the stop time parameter for the t=
+ * timespec token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * stop_time Ptr to the stop time string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_time_stop (sdp_t *sdp_p, const char *stop_time)
+{
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ sdp_p->timespec_p->start_time[0] = '\0';
+ sdp_p->timespec_p->stop_time[0] = '\0';
+ }
+ sstrncpy(sdp_p->timespec_p->stop_time, stop_time,
+ sizeof(sdp_p->timespec_p->stop_time));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_encryption_valid
+ * Description: Returns true or false depending on whether the encryption k=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the k= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_encryption_valid (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ if ((encrypt_p->encrypt_type == SDP_ENCRYPT_INVALID) ||
+ ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
+ (encrypt_p->encrypt_key[0] == '\0'))) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_encryption_method
+ * Description: Returns the encryption method parameter from the k=
+ * encryption token line. If encryption method has not been
+ * set SDP_ENCRYPT_INVALID will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Encryption method or SDP_ENCRYPT_INVALID.
+ */
+sdp_encrypt_type_e sdp_get_encryption_method (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_ENCRYPT_INVALID);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ return (encrypt_p->encrypt_type);
+}
+
+/* Function: sdp_get_encryption_key
+ * Description: Returns a pointer to the encryption key parameter
+ * from the k= encryption token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Ptr to encryption key or NULL.
+ */
+const char *sdp_get_encryption_key (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ return (encrypt_p->encrypt_key);
+}
+
+/* Function: sdp_connection_valid
+ * Description: Returns true or false depending on whether the connection c=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_connection_valid (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ /*if network type is ATM . then allow c= line without address type
+ * and address . This is a special case to cover PVC
+ */
+ if (conn_p->nettype == SDP_NT_ATM &&
+ conn_p->addrtype == SDP_AT_INVALID) {
+ return TRUE;
+ }
+
+ if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
+ (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
+ (conn_p->conn_addr[0] == '\0')) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_bandwidth_valid
+ * Description: Returns true or false depending on whether the bandwidth b=
+ * token line has been defined for this SDP at the given level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_bandwidth_valid (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_bw_data_t *bw_data_p;
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+ if (bw_data_p != NULL) {
+ if ((bw_data_p->bw_modifier < SDP_BW_MODIFIER_AS) ||
+ (bw_data_p->bw_modifier >= SDP_MAX_BW_MODIFIER_VAL)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+/*
+ * sdp_bw_line_exists
+ *
+ * Description: This api retruns true if there exists a bw line at the
+ * instance and level specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: TRUE or FALSE
+ */
+tinybool sdp_bw_line_exists (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_bw_data_t *bw_data_p;
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+ if (bw_data_p != NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/* Function: sdp_get_conn_nettype
+ * Description: Returns the network type parameter from the c=
+ * connection token line. If network type has not been
+ * set SDP_NT_INVALID will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Network type or SDP_NT_INVALID.
+ */
+sdp_nettype_e sdp_get_conn_nettype (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_NT_INVALID);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->nettype);
+}
+
+/* Function: sdp_get_conn_addrtype
+ * Description: Returns the address type parameter from the c=
+ * connection token line. If address type has not been
+ * set SDP_AT_INVALID will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Address type or SDP_AT_INVALID.
+ */
+sdp_addrtype_e sdp_get_conn_addrtype (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_AT_INVALID);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->addrtype);
+}
+
+/* Function: sdp_get_conn_address
+ * Description: Returns a pointer to the address parameter
+ * from the c= connection token line. Value is returned as a
+ * const ptr and so cannot be modified by the application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Ptr to address or NULL.
+ */
+const char *sdp_get_conn_address (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ return (conn_p->conn_addr);
+}
+
+/* Function: sdp_is_mcast_addr
+ * Description: Returns a boolean to indicate if the addr is multicast in
+ * the c=line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: TRUE if the addr is multicast, FALSE if not.
+ */
+
+tinybool sdp_is_mcast_addr (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return (FALSE);
+ }
+ }
+
+ if ((conn_p) && (conn_p->is_multicast)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/* Function: sdp_get_mcast_ttl
+ * Description: Get the time to live(ttl) value for the multicast address
+ * if present.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Multicast address - Time to live (ttl) value
+ */
+
+int32_t sdp_get_mcast_ttl (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ uint16_t ttl=0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return SDP_INVALID_VALUE;
+ }
+ }
+
+ if (conn_p) {
+ ttl = conn_p->ttl;
+ }
+ return ttl;
+}
+
+/* Function: sdp_get_mcast_num_of_addresses
+ * Description: Get the number of addresses value for the multicast address
+ * if present.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: Multicast address - number of addresses value
+ */
+
+int32_t sdp_get_mcast_num_of_addresses (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ uint16_t num_addr = 0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p != NULL) {
+ conn_p = &(mca_p->conn);
+ } else {
+ return (SDP_INVALID_VALUE);
+ }
+ }
+
+ if (conn_p) {
+ num_addr = conn_p->num_of_addresses;
+ }
+ return num_addr;
+}
+/* Function: sdp_set_conn_nettype
+ * Description: Sets the value of the network type parameter for the c=
+ * connection token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * nettype Network type for the connection line.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_conn_nettype (sdp_t *sdp_p, uint16_t level,
+ sdp_nettype_e nettype)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ conn_p->nettype = nettype;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_conn_addrtype
+ * Description: Sets the value of the address type parameter for the c=
+ * connection token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * addrtype Address type for the connection line.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_conn_addrtype (sdp_t *sdp_p, uint16_t level,
+ sdp_addrtype_e addrtype)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ conn_p->addrtype = addrtype;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_conn_address
+ * Description: Sets the value of the address parameter for the c=
+ * connection token line. The string is copied into the
+ * SDP structure so application memory will not be
+ * referenced by the SDP lib.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * either SDP_SESSION_LEVEL or 1-n specifying a
+ * media line level.
+ * address Ptr to the address string.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_set_conn_address (sdp_t *sdp_p, uint16_t level,
+ const char *address)
+{
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ sstrncpy(conn_p->conn_addr, address, sizeof(conn_p->conn_addr));
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_media_line_valid
+ * Description: Returns true or false depending on whether the specified
+ * media line m= has been defined for this SDP. The
+ * SDP_SESSION_LEVEL level is not valid for this check since,
+ * by definition, this is a media level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the c= line. Will be
+ * 1-n specifying a media line level.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_media_line_valid (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (FALSE);
+ }
+
+ /* Validate params for this media line */
+ if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
+ (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES) ||
+ (mca_p->num_payloads == 0)) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_get_num_media_lines
+ * Description: Returns the number of media lines associated with the SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * Returns: Number of media lines.
+ */
+uint16_t sdp_get_num_media_lines (sdp_t *sdp_p)
+{
+ return (sdp_p->mca_count);
+}
+
+/* Function: sdp_get_media_type
+ * Description: Returns the media type parameter from the m=
+ * media token line. If media type has not been
+ * set SDP_MEDIA_INVALID will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_get_media_type (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_MEDIA_INVALID);
+ }
+
+ return (mca_p->media);
+}
+
+/* Function: sdp_get_media_line_number
+ * Description: Returns the line number in the SDP the media
+ * section starts on. Only set if SDP has been parsed
+ * (rather than built).
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Line number (0 if not found or if locally built)
+ */
+uint32_t sdp_get_media_line_number (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return 0;
+ }
+
+ return (mca_p->line_number);
+}
+
+/* Function: sdp_get_media_port_format
+ * Description: Returns the port format type associated with the m=
+ * media token line. If port format type has not been
+ * set SDP_PORT_FORMAT_INVALID will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port format type or SDP_PORT_FORMAT_INVALID.
+ */
+sdp_port_format_e sdp_get_media_port_format (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_PORT_FORMAT_INVALID);
+ }
+
+ return (mca_p->port_format);
+}
+
+/* Function: sdp_get_media_portnum
+ * Description: Returns the port number associated with the m=
+ * media token line. If port number has not been
+ * set SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port number or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_media_portnum (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_NUM_ONLY) &&
+ (mca_p->port_format != SDP_PORT_NUM_COUNT) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Port num not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->port);
+}
+
+/* Function: sdp_get_media_portcount
+ * Description: Returns the port count associated with the m=
+ * media token line. If port count has not been
+ * set SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Port count or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_media_portcount (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if (mca_p->port_format != SDP_PORT_NUM_COUNT) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Port count not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->num_ports);
+}
+
+/* Function: sdp_get_media_vpi
+ * Description: Returns the VPI parameter associated with the m=
+ * media token line. If VPI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VPI or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_media_vpi (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VPI not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->vpi);
+}
+
+/* Function: sdp_get_media_vci
+ * Description: Returns the VCI parameter associated with the m=
+ * media token line. If VCI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VCI or zero.
+ */
+uint32_t sdp_get_media_vci (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VCI not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+
+ return (mca_p->vci);
+}
+
+/* Function: sdp_get_media_vcci
+ * Description: Returns the VCCI parameter associated with the m=
+ * media token line. If VCCI has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: VCCI or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_media_vcci (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VCCI) &&
+ (mca_p->port_format != SDP_PORT_VCCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s VCCI not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->vcci);
+}
+
+/* Function: sdp_get_media_cid
+ * Description: Returns the CID parameter associated with the m=
+ * media token line. If CID has not been set
+ * SDP_INVALID_VALUE will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: CID or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_media_cid (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_INVALID_VALUE);
+ }
+
+ /* Make sure port number is valid for the specified format. */
+ if ((mca_p->port_format != SDP_PORT_VCCI_CID) &&
+ (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CID not valid for media line %u",
+ sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+
+ return (mca_p->cid);
+}
+
+/* Function: sdp_get_media_transport
+ * Description: Returns the transport type parameter associated with the m=
+ * media token line. If transport type has not been set
+ * SDP_TRANSPORT_INVALID will be returned. If the transport
+ * type is one of the AAL2 variants, the profile routines below
+ * should be used to access multiple profile types and payload
+ * lists per m= line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: CID or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_get_media_transport (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ return (mca_p->transport);
+}
+
+/* Function: sdp_get_media_num_profiles
+ * Description: Returns the number of profiles associated with the m=
+ * media token line. If the media line is invalid, zero will
+ * be returned. Application must validate the media line
+ * before using this routine. Multiple profile types per
+ * media line is currently only used for AAL2. If the appl
+ * detects that the transport type is one of the AAL2 types,
+ * it should use these profile access routines to access the
+ * profile types and payload list for each.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Number of profiles or zero.
+ */
+uint16_t sdp_get_media_num_profiles (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if (mca_p->media_profiles_p == NULL) {
+ return (0);
+ } else {
+ return (mca_p->media_profiles_p->num_profiles);
+ }
+}
+
+/* Function: sdp_get_media_profile
+ * Description: Returns the specified profile type associated with the m=
+ * media token line. If the media line or profile number is
+ * invalid, SDP_TRANSPORT_INVALID will be returned.
+ * Applications must validate the media line before using this
+ * routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * profile_num The specific profile type number to be retrieved.
+ * Returns: The profile type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_get_media_profile (sdp_t *sdp_p, uint16_t level,
+ uint16_t profile_num)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_TRANSPORT_INVALID);
+ }
+
+ if ((profile_num < 1) ||
+ (profile_num > mca_p->media_profiles_p->num_profiles)) {
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ return (mca_p->media_profiles_p->profile[profile_num-1]);
+ }
+}
+
+/* Function: sdp_get_media_num_payload_types
+ * Description: Returns the number of payload types associated with the m=
+ * media token line. If the media line is invalid, zero will
+ * be returned. Application must validate the media line
+ * before using this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * Returns: Number of payload types or zero.
+ */
+uint16_t sdp_get_media_num_payload_types (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ return (mca_p->num_payloads);
+}
+
+/* Function: sdp_get_media_profile_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified profile on the m= media token line. If the
+ * media line or profile number is invalid, zero will
+ * be returned. Application must validate the media line
+ * and profile before using this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * profile_num The specific profile number. Will be 1-n.
+ * Returns: Number of payload types or zero.
+ */
+uint16_t sdp_get_media_profile_num_payload_types (sdp_t *sdp_p, uint16_t level,
+ uint16_t profile_num)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if ((profile_num < 1) ||
+ (profile_num > mca_p->media_profiles_p->num_profiles)) {
+ return (0);
+ } else {
+ return (mca_p->media_profiles_p->num_payloads[profile_num-1]);
+ }
+}
+
+rtp_ptype sdp_get_known_payload_type(sdp_t *sdp_p,
+ uint16_t level,
+ uint16_t payload_type_raw) {
+ sdp_attr_t *attr_p;
+ sdp_transport_map_t *rtpmap;
+ uint16_t pack_mode = 0; /*default 0, if remote did not provide any */
+ const char *encname = NULL;
+ uint16_t num_a_lines = 0;
+ int i;
+
+ /*
+ * Get number of RTPMAP attributes for the media line
+ */
+ (void) sdp_attr_num_instances(sdp_p, level, 0, SDP_ATTR_RTPMAP,
+ &num_a_lines);
+
+ /*
+ * Loop through media line RTPMAP attributes.
+ */
+ for (i = 0; i < num_a_lines; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTPMAP, (i + 1));
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.",
+ sdp_p->debug_str,
+ (unsigned)level,
+ (unsigned)(i + 1));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (RTP_NONE);
+ }
+
+ rtpmap = &(attr_p->attr.transport_map);
+
+ if (rtpmap->payload_num == payload_type_raw) {
+ encname = rtpmap->encname;
+ if (encname) {
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ILBC) == 0) {
+ return (RTP_ILBC);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_L16_256K) == 0) {
+ return (RTP_L16);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ISAC) == 0) {
+ return (RTP_ISAC);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_OPUS) == 0) {
+ return (RTP_OPUS);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_PCMU) == 0) {
+ return (RTP_PCMU);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_PCMA) == 0) {
+ return (RTP_PCMA);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_G722) == 0) {
+ return (RTP_G722);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_H264) == 0) {
+ int fmtp_inst = sdp_find_fmtp_inst(sdp_p, level, rtpmap->payload_num);
+ if (fmtp_inst < 0) {
+ return (RTP_H264_P0);
+ } else {
+ sdp_attr_get_fmtp_pack_mode(sdp_p, level, 0, (uint16_t) fmtp_inst, &pack_mode);
+ if (pack_mode == SDP_DEFAULT_PACKETIZATION_MODE_VALUE) {
+ return (RTP_H264_P0);
+ } else {
+ return (RTP_H264_P1);
+ }
+ }
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP8) == 0) {
+ return (RTP_VP8);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP9) == 0) {
+ return (RTP_VP9);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_RED) == 0) {
+ return (RTP_RED);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ULPFEC) == 0) {
+ return (RTP_ULPFEC);
+ }
+ if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_TELEPHONE_EVENT) == 0) {
+ return (RTP_TELEPHONE_EVENT);
+ }
+ }
+ }
+ }
+
+ return (RTP_NONE);
+}
+
+/* Function: sdp_get_media_payload_type
+ * Description: Returns the payload type of the specified payload for the m=
+ * media token line. If the media line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the media line before using this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * payload_num Number of the payload type to retrieve. The
+ * range is (1 - max num payloads).
+ * indicator Returns the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: Payload type or zero.
+ */
+uint32_t sdp_get_media_payload_type (sdp_t *sdp_p, uint16_t level, uint16_t payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_mca_t *mca_p;
+ rtp_ptype ptype;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ if ((payload_num < 1) || (payload_num > mca_p->num_payloads)) {
+ return (0);
+ }
+
+ *indicator = mca_p->payload_indicator[payload_num-1];
+ if ((mca_p->payload_type[payload_num-1] >= SDP_MIN_DYNAMIC_PAYLOAD) &&
+ (mca_p->payload_type[payload_num-1] <= SDP_MAX_DYNAMIC_PAYLOAD)) {
+ ptype = sdp_get_known_payload_type(sdp_p,
+ level,
+ mca_p->payload_type[payload_num-1]);
+ if (ptype != RTP_NONE) {
+ return (SET_PAYLOAD_TYPE_WITH_DYNAMIC(
+ mca_p->payload_type[payload_num-1], ptype));
+ }
+
+ }
+ return (mca_p->payload_type[payload_num-1]);
+}
+
+/* Function: sdp_get_media_profile_payload_type
+ * Description: Returns the payload type of the specified payload for the m=
+ * media token line. If the media line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the media line before using this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to of the m= media line. Will be 1-n.
+ * payload_num Number of the payload type to retrieve. The
+ * range is (1 - max num payloads).
+ * indicator Returns the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: Payload type or zero.
+ */
+uint32_t sdp_get_media_profile_payload_type (sdp_t *sdp_p, uint16_t level, uint16_t prof_num,
+ uint16_t payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_mca_t *mca_p;
+ sdp_media_profiles_t *prof_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (0);
+ }
+
+ prof_p = mca_p->media_profiles_p;
+ if ((prof_num < 1) ||
+ (prof_num > prof_p->num_profiles)) {
+ return (0);
+ }
+
+ if ((payload_num < 1) ||
+ (payload_num > prof_p->num_payloads[prof_num-1])) {
+ return (0);
+ }
+
+ *indicator = prof_p->payload_indicator[prof_num-1][payload_num-1];
+ return (prof_p->payload_type[prof_num-1][payload_num-1]);
+}
+
+/* Function: sdp_insert_media_line
+ * Description: Insert a new media line at the level specified for the
+ * given SDP.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The new media level to insert. Will be 1-n.
+ * Returns: SDP_SUCCESS, SDP_NO_RESOURCE, or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_insert_media_line (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+ sdp_mca_t *new_mca_p;
+
+ if ((level < 1) || (level > (sdp_p->mca_count+1))) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid media line (%u) to insert, max is "
+ "(%u).", sdp_p->debug_str, (unsigned)level, (unsigned)sdp_p->mca_count);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Allocate resource for new media stream. */
+ new_mca_p = sdp_alloc_mca(0);
+ if (new_mca_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ if (level == 1) {
+ /* We're inserting the first media line */
+ new_mca_p->next_p = sdp_p->mca_p;
+ sdp_p->mca_p = new_mca_p;
+ } else {
+ /* Find the pointer to the media stream just prior to where
+ * we want to insert the new stream.
+ */
+ mca_p = sdp_find_media_level(sdp_p, (uint16_t)(level-1));
+ if (mca_p == NULL) {
+ SDP_FREE(new_mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ new_mca_p->next_p = mca_p->next_p;
+ mca_p->next_p = new_mca_p;
+ }
+
+ sdp_p->mca_count++;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_type
+ * Description: Sets the value of the media type parameter for the m=
+ * media token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * media Media type for the media line.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_type (sdp_t *sdp_p, uint16_t level, sdp_media_e media)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->media = media;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_set_media_portnum
+ * Description: Sets the value of the port number parameter for the m=
+ * media token line. If the port number is not valid with the
+ * port format specified for the media line, this call will
+ * fail.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * portnum Port number to set.
+ * sctpport sctp port for application m= line
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_portnum (sdp_t *sdp_p, uint16_t level, int32_t portnum, int32_t sctp_port)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->port = portnum;
+ mca_p->sctpport = sctp_port;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_media_sctp_port
+ * Description: Gets the value of the sctp port number parameter for the m=
+ * media token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * Returns: sctp_port or -1 on failure
+ */
+int32_t sdp_get_media_sctp_port(sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (!mca_p) {
+ sdp_p->conf_p->num_invalid_param++;
+ return -1;
+ }
+
+ return mca_p->sctpport;
+}
+
+/* Function: sdp_set_media_transport
+ * Description: Sets the value of the transport type parameter for the m=
+ * media token line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to set the param. Will be 1-n.
+ * transport The transport type to set.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_set_media_transport (sdp_t *sdp_p, uint16_t level,
+ sdp_transport_e transport)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->transport = transport;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_profile
+ * Description: Add a new profile type for the m= media token line. This is
+ * used for AAL2 transport/profile types where more than one can
+ * be specified per media line. All other transport types should
+ * use the other transport access routines rather than this.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to add the param. Will be 1-n.
+ * profile The profile type to add.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_profile (sdp_t *sdp_p, uint16_t level,
+ sdp_transport_e profile)
+{
+ uint16_t prof_num;
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->media_profiles_p == NULL) {
+ mca_p->media_profiles_p = (sdp_media_profiles_t *) \
+ SDP_MALLOC(sizeof(sdp_media_profiles_t));
+ if (mca_p->media_profiles_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ } else {
+ mca_p->media_profiles_p->num_profiles = 0;
+ /* Set the transport type to this first profile type. */
+ mca_p->transport = profile;
+ }
+ }
+
+ if (mca_p->media_profiles_p->num_profiles >= SDP_MAX_PROFILES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of media profiles already specified"
+ " for media level %u", sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ prof_num = mca_p->media_profiles_p->num_profiles++;
+ mca_p->media_profiles_p->profile[prof_num] = profile;
+ mca_p->media_profiles_p->num_payloads[prof_num] = 0;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_payload_type
+ * Description: Add a new payload type for the media line at the level
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to add the payload. Will be 1-n.
+ * payload_type The new payload type.
+ * indicator Defines the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->num_payloads == SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of payload types already defined "
+ "for media line %u", sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ mca_p->payload_indicator[mca_p->num_payloads] = indicator;
+ mca_p->payload_type[mca_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_add_media_profile_payload_type
+ * Description: Add a new payload type for the media line at the level
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The media level to add the payload. Will be 1-n.
+ * prof_num The profile number to add the payload type.
+ * payload_type The new payload type.
+ * indicator Defines the type of payload returned, either
+ * NUMERIC or ENUM.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_add_media_profile_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t prof_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator)
+{
+ uint16_t num_payloads;
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if ((prof_num < 1) ||
+ (prof_num > mca_p->media_profiles_p->num_profiles)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid profile number (%u) for set profile "
+ " payload type", sdp_p->debug_str, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (mca_p->media_profiles_p->num_payloads[prof_num-1] ==
+ SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Max number of profile payload types already "
+ "defined profile %u on media line %u",
+ sdp_p->debug_str, (unsigned)prof_num, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Get the current num payloads for this profile, and inc the number
+ * of payloads at the same time. Then store the new payload type. */
+ num_payloads = mca_p->media_profiles_p->num_payloads[prof_num-1]++;
+ mca_p->media_profiles_p->payload_indicator[prof_num-1][num_payloads] =
+ indicator;
+ mca_p->media_profiles_p->payload_type[prof_num-1][num_payloads] =
+ payload_type;
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_find_bw_line
+ *
+ * This helper function locates a specific bw line instance given the
+ * sdp, the level and the instance number of the bw line.
+ *
+ * Returns: Pointer to the sdp_bw_data_t instance, or NULL.
+ */
+sdp_bw_data_t* sdp_find_bw_line (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_mca_t *mca_p;
+ int bw_attr_count=0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+ bw_attr_count++;
+ if (bw_attr_count == inst_num) {
+ return bw_data_p;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * sdp_copy_all_bw_lines
+ *
+ * Appends all the bw lines from the specified level of the orig sdp to the
+ * specified level of the dst sdp.
+ *
+ * Parameters: src_sdp_p The source SDP handle.
+ * dst_sdp_p The dest SDP handle.
+ * src_level The level in the src sdp from where to get the
+ * attributes.
+ * dst_level The level in the dst sdp where to put the
+ * attributes.
+ * Returns: SDP_SUCCESS Attributes were successfully copied.
+ */
+sdp_result_e sdp_copy_all_bw_lines (sdp_t *src_sdp_p, sdp_t *dst_sdp_p,
+ uint16_t src_level, uint16_t dst_level)
+{
+ sdp_bw_data_t *orig_bw_data_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_bw_t *src_bw_p;
+ sdp_bw_t *dst_bw_p;
+ sdp_mca_t *mca_p;
+
+ /* Find src bw list */
+ if (src_level == SDP_SESSION_LEVEL) {
+ src_bw_p = &(src_sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(src_sdp_p, src_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid src media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, (unsigned)src_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ src_bw_p = &(mca_p->bw);
+ }
+
+ /* Find dst bw list */
+ if (dst_level == SDP_SESSION_LEVEL) {
+ dst_bw_p = &(dst_sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(dst_sdp_p, dst_level);
+ if (mca_p == NULL) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Invalid dst media level (%u) for copy all "
+ "attrs ", src_sdp_p->debug_str, (unsigned)dst_level);
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+ dst_bw_p = &(mca_p->bw);
+ }
+
+ orig_bw_data_p = src_bw_p->bw_data_list;
+ while (orig_bw_data_p) {
+ /* For ever bw line in the src, allocate a new one for the dst */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = orig_bw_data_p->bw_modifier;
+ new_bw_data_p->bw_val = orig_bw_data_p->bw_val;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (dst_bw_p->bw_data_list == NULL) {
+ dst_bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = dst_bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ dst_bw_p->bw_data_count++;
+
+ orig_bw_data_p = orig_bw_data_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_bw_modifier
+ * Description: Returns the bandwidth modifier parameter from the b=
+ * line. If no bw modifier has been set ,
+ * SDP_BW_MODIFIER_UNSUPPORTED will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level from which to get the bw modifier.
+ * inst_num instance number of bw line at that level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: Valid modifer value or SDP_BW_MODIFIER_UNSUPPORTED.
+ */
+sdp_bw_modifier_e sdp_get_bw_modifier (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_bw_data_t *bw_data_p;
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+
+ if (bw_data_p) {
+ return (bw_data_p->bw_modifier);
+ } else {
+ return (SDP_BW_MODIFIER_UNSUPPORTED);
+ }
+}
+
+/* Function: sdp_get_bw_value
+ * Description: Returns the bandwidth value parameter from the b=
+ * line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level from which to get the bw value.
+ * inst_num instance number of bw line at the level. The first
+ * instance has a inst_num of 1 and so on.
+ * Returns: A valid numerical bw value or SDP_INVALID_VALUE.
+ */
+int32_t sdp_get_bw_value (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_bw_data_t *bw_data_p;
+
+ bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num);
+
+ if (bw_data_p) {
+ return (bw_data_p->bw_val);
+ } else {
+ return (SDP_INVALID_VALUE);
+ }
+}
+
+/*
+ * sdp_get_num_bw_lines
+ *
+ * Returns the number of bw lines are present at a given level.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level at which the count of bw lines is required
+ *
+ * Returns: A valid count or SDP_INVALID_VALUE
+ */
+int32_t sdp_get_num_bw_lines (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_bw_t *bw_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ return (bw_p->bw_data_count);
+}
+
+/*
+ * sdp_add_new_bw_line
+ *
+ * To specify bandwidth parameters at any level, a bw line must first be
+ * added at that level using this function. After this addition, you can set
+ * the properties of the added bw line by using sdp_set_bw().
+ *
+ * Note carefully though, that since there can be multiple instances of bw
+ * lines at any level, you must specify the instance number when setting
+ * or getting the properties of a bw line at any level.
+ *
+ * This function returns within the inst_num variable, the instance number
+ * of the created bw_line at that level. The instance number is 1-based.
+ * For example:
+ * v=0 #Session Level
+ * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ * s=SDP Seminar
+ * c=IN IP4 10.1.0.2
+ * t=0 0
+ * b=AS:60 # instance number 1
+ * b=TIAS:50780 # instance number 2
+ * m=audio 1234 RTP/AVP 0 101 102 # 1st Media level
+ * b=AS:12 # instance number 1
+ * b=TIAS:8480 # instance number 2
+ * m=audio 1234 RTP/AVP 0 101 102 # 2nd Media level
+ * b=AS:20 # instance number 1
+ *
+ * Parameters:
+ * sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to create the bw line.
+ * bw_modifier The Type of bandwidth, CT, AS or TIAS.
+ * *inst_num This memory is set with the instance number of the newly
+ * created bw line instance.
+ */
+sdp_result_e sdp_add_new_bw_line (sdp_t *sdp_p, uint16_t level, sdp_bw_modifier_e bw_modifier, uint16_t *inst_num)
+{
+ sdp_bw_t *bw_p;
+ sdp_mca_t *mca_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_bw_data_t *bw_data_p = NULL;
+
+ *inst_num = 0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ //see if a bw line already exist for this bw_modifier.
+ for(bw_data_p = bw_p->bw_data_list; bw_data_p != NULL; bw_data_p = bw_data_p->next_p) {
+ ++(*inst_num);
+ if (bw_data_p->bw_modifier == bw_modifier) {
+ return (SDP_SUCCESS);
+ }
+ }
+
+ /*
+ * Allocate a new sdp_bw_data_t instance and set it's values from the
+ * input parameters.
+ */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
+ new_bw_data_p->bw_val = 0;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (bw_p->bw_data_list == NULL) {
+ bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+
+ /*sa_ignore EMPTYLOOP*/
+ ; /* Do nothing. */
+ }
+
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ *inst_num = ++bw_p->bw_data_count;
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_mid_value
+ * Description: Returns the mid value parameter from the a= mid: line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level SDP_MEDIA_LEVEL
+ * Returns: mid value.
+ */
+int32_t sdp_get_mid_value (sdp_t *sdp_p, uint16_t level)
+{
+ sdp_mca_t *mca_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ return (mca_p->mid);
+}
+
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
new file mode 100644
index 000000000..e3afa2637
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr.c
@@ -0,0 +1,5120 @@
+/* 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/. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "plstr.h"
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+#include "sdp_base64.h"
+
+#include "CSFLog.h"
+
+static const char* logTag = "sdp_attr";
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds name-value pair where value is char*
+ */
+#define FMTP_BUILD_STRING(condition, name, value) \
+ if ((condition)) { \
+ sdp_append_name_and_string(fs, (name), (value), semicolon); \
+ semicolon = TRUE; \
+ }
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds name-value pair where value is unsigned
+ */
+#define FMTP_BUILD_UNSIGNED(condition, name, value) \
+ if ((condition)) { \
+ sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
+ semicolon = TRUE; \
+ }
+
+/*
+ * Macro for sdp_build_attr_fmtp
+ * Adds flag string on condition
+ */
+#define FMTP_BUILD_FLAG(condition, name) \
+ if ((condition)) { \
+ if (semicolon) { \
+ flex_string_append(fs, ";"); \
+ } \
+ flex_string_append(fs, name); \
+ semicolon = TRUE; \
+ }
+
+static int find_token_enum(const char *attr_name,
+ sdp_t *sdp_p,
+ const char **ptr,
+ const sdp_namearray_t *types,
+ int type_count,
+ int unknown_value)
+{
+ sdp_result_e result = SDP_SUCCESS;
+ char tmp[SDP_MAX_STRING_LEN+1];
+ int i;
+
+ *ptr = sdp_getnextstrtok(*ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: problem parsing %s", sdp_p->debug_str, attr_name);
+ sdp_p->conf_p->num_invalid_param++;
+ return -1;
+ }
+
+ for (i=0; i < type_count; i++) {
+ if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) {
+ return i;
+ }
+ }
+ return unknown_value;
+}
+
+/*
+ * Helper function for adding nv-pair where value is string.
+ */
+static void sdp_append_name_and_string(flex_string *fs,
+ const char *name,
+ const char *value,
+ tinybool semicolon)
+{
+ flex_string_sprintf(fs, "%s%s=%s",
+ semicolon ? ";" : "",
+ name,
+ value);
+}
+
+/*
+ * Helper function for adding nv-pair where value is unsigned.
+ */
+static void sdp_append_name_and_unsigned(flex_string *fs,
+ const char *name,
+ unsigned int value,
+ tinybool semicolon)
+{
+ flex_string_sprintf(fs, "%s%s=%u",
+ semicolon ? ";" : "",
+ name,
+ value);
+}
+
+/* Function: sdp_parse_attribute
+ * Description: Figure out the type of attribute and call the appropriate
+ * parsing routine. If parsing errors are encountered,
+ * warnings will be printed and the attribute will be ignored.
+ * Unrecognized/invalid attributes do not cause overall parsing
+ * errors. All errors detected are noted as warnings.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * ptr Pointer to the attribute string to parse.
+ */
+sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int i;
+ uint8_t xcpar_flag = FALSE;
+ sdp_result_e result;
+ sdp_mca_t *mca_p=NULL;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *next_attr_p;
+ sdp_attr_t *prev_attr_p = NULL;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Validate the level */
+ if (level != SDP_SESSION_LEVEL) {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ }
+
+ /* Find the attribute type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+ if (ptr == NULL) {
+ sdp_parse_error(sdp_p,
+ "%s No attribute type specified, parse failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (ptr[0] == ':') {
+ /* Skip the ':' char for parsing attribute parameters. */
+ ptr++;
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No attribute type specified, parse failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (attr_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ attr_p->line_number = sdp_p->parse_line;
+ attr_p->type = SDP_ATTR_INVALID;
+ attr_p->next_p = NULL;
+ for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
+ attr_p->type = (sdp_attr_e)i;
+ break;
+ }
+ }
+ if (attr_p->type == SDP_ATTR_INVALID) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unrecognized attribute (%s) ",
+ sdp_p->debug_str, tmp);
+ sdp_free_attr(attr_p);
+ return (SDP_SUCCESS);
+ }
+
+ /* If this is an X-cpar or cpar attribute, set the flag. The attribute
+ * type will be changed by the parse. */
+ if ((attr_p->type == SDP_ATTR_X_CPAR) ||
+ (attr_p->type == SDP_ATTR_CPAR)) {
+ xcpar_flag = TRUE;
+ }
+
+ /* Parse the attribute. */
+ result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
+ if (result != SDP_SUCCESS) {
+ sdp_free_attr(attr_p);
+ /* Return success so the parse won't fail. We don't want to
+ * fail on errors with attributes but just ignore them.
+ */
+ return (SDP_SUCCESS);
+ }
+
+ /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
+ * structure, so we're finished.
+ */
+ if (xcpar_flag == TRUE) {
+ return (result);
+ }
+
+ /* Add the attribute in the appropriate place. */
+ if (level == SDP_SESSION_LEVEL) {
+ for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
+ prev_attr_p = next_attr_p,
+ next_attr_p = next_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ if (prev_attr_p == NULL) {
+ sdp_p->sess_attrs_p = attr_p;
+ } else {
+ prev_attr_p->next_p = attr_p;
+ }
+ } else {
+ for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
+ prev_attr_p = next_attr_p,
+ next_attr_p = next_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ if (prev_attr_p == NULL) {
+ mca_p->media_attrs_p = attr_p;
+ } else {
+ prev_attr_p->next_p = attr_p;
+ }
+ }
+
+ return (result);
+}
+
+/* Build all of the attributes defined for the specified level. */
+sdp_result_e sdp_build_attribute (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p=NULL;
+ sdp_result_e result;
+
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ attr_p = mca_p->media_attrs_p;
+ }
+ /* Re-initialize the current capability number for this new level. */
+ sdp_p->cur_cap_num = 1;
+
+ /* Build all of the attributes for this level. Note that if there
+ * is a problem building an attribute, we don't fail but just ignore it.*/
+ while (attr_p != NULL) {
+ if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
+ sdp_p->debug_str, (unsigned)attr_p->type);
+ }
+ } else {
+ result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
+
+ if (result != SDP_SUCCESS) {
+ CSFLogError(logTag, "%s error building attribute %d", __FUNCTION__, result);
+ return result;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ attr_p = attr_p->next_p;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
+ sizeof(attr_p->attr.string_val), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.string_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.string_val);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Numeric token for %s attribute not found",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %u", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.u32_val);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
+ attr_p->attr.boolean_val = FALSE;
+ } else {
+ attr_p->attr.boolean_val= TRUE;
+ }
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Boolean token for %s attribute not found",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ if (attr_p->attr.boolean_val) {
+ SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ } else {
+ SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.boolean_val ? "1" : "0");
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_attr_maxprate
+ *
+ * This function parses maxprate attribute lines. The ABNF for this a=
+ * line is:
+ * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
+ * packet-rate = 1*DIGIT ["." 1*DIGIT]
+ *
+ * Returns:
+ * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
+ * packet-rate is not in the right format as per
+ * the ABNF.
+ *
+ * SDP_SUCCESS - If we are able to successfully parse the a= line.
+ */
+sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
+ sizeof(attr_p->attr.string_val), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
+ sdp_parse_error(sdp_p,
+ "%s is not a valid maxprate value.",
+ attr_p->attr.string_val);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.string_val);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+/*
+ * sdp_attr_fmtp_no_value
+ * Helper function for sending the warning when a parameter value is
+ * missing.
+ *
+ */
+static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name)
+{
+ sdp_parse_error(sdp,
+ "%s Warning: No %s value specified for fmtp attribute",
+ sdp->debug_str, param_name);
+ sdp->conf_p->num_invalid_param++;
+}
+
+/*
+ * sdp_attr_fmtp_invalid_value
+ * Helper function for sending the warning when a parameter value is
+ * incorrect.
+ *
+ */
+static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name,
+ const char* param_value)
+{
+ sdp_parse_error(sdp,
+ "%s Warning: Invalid %s: %s specified for fmtp attribute",
+ sdp->debug_str, param_name, param_value);
+ sdp->conf_p->num_invalid_param++;
+}
+
+/*
+ * sdp_verify_attr_fmtp_telephone_event
+ * Helper function for verifying the telephone-event fmtp format
+ */
+static sdp_result_e sdp_verify_attr_fmtp_telephone_event(char *fmtpVal)
+{
+ size_t len = PL_strlen(fmtpVal);
+
+ // make sure the basics are good:
+ // - at least 1 character
+ // - no illegal chars
+ // - first char is a number
+ if (len < 1
+ || strspn(fmtpVal, "0123456789,-") != len
+ || PL_strstr(fmtpVal, ",,")
+ || fmtpVal[len-1] == ','
+ || !('0' <= fmtpVal[0] && fmtpVal[0] <= '9')) {
+ return SDP_INVALID_PARAMETER;
+ }
+
+ // Now that we've passed the basic sanity test, copy the string so we
+ // can tokenize and check the format of the tokens without disturbing
+ // the input string.
+ char dtmf_tones[SDP_MAX_STRING_LEN+1];
+ PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));
+
+ char *strtok_state;
+ char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state);
+
+ while (temp != NULL) {
+ len = PL_strlen(temp);
+ if (len > 5) {
+ // an example of a max size token is "11-15", so if the
+ // token is longer than 5 it is bad
+ return SDP_INVALID_PARAMETER;
+ }
+
+ // case where we have 1 or 2 characters, example 4 or 23
+ if (len < 3 && strspn(temp, "0123456789") != len) {
+ return SDP_INVALID_PARAMETER;
+ } else if (len >= 3) {
+ // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
+ sdp_result_e result1 = SDP_SUCCESS;
+ sdp_result_e result2 = SDP_SUCCESS;
+ uint8_t low_val;
+ uint8_t high_val;
+ low_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
+ "-", &result1);
+ high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
+ "-", &result2);
+ if (temp[0] // we don't want to find a second hyphen
+ || result1 != SDP_SUCCESS
+ || result2 != SDP_SUCCESS) {
+ return SDP_INVALID_PARAMETER;
+ }
+
+ if (low_val > 99
+ || high_val > 99
+ || high_val <= low_val) {
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ }
+
+ return SDP_SUCCESS;
+}
+
+/* Note: The fmtp attribute formats currently handled are:
+ * fmtp:<payload type> <event>,<event>...
+ * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
+ * [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more
+ * Other FMTP params as per H.263, H.263+, H.264 codec support.
+ * Note -"value" is a numeric value > 0 and each event is a
+ * single number or a range separated by a '-'.
+ * Example: fmtp:101 1,3-15,20
+ * Video codecs have annexes that can be listed in the following legal formats:
+ * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
+ * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
+ * c) a=fmtp:34 param1=token;D;I;J
+ *
+ */
+sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p,
+ const char** fmtp_ptr,
+ const char* fmtp_name,
+ char* buf,
+ size_t buf_size,
+ char** tok)
+{
+ sdp_result_e result1 = SDP_SUCCESS;
+
+ *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, fmtp_name);
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+ *tok = buf;
+ (*tok)++;
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
+ const char** fmtp_ptr,
+ const char* fmtp_name,
+ char* buf,
+ size_t buf_size,
+ char** tok,
+ unsigned long* strtoul_result,
+ unsigned long illegal_value,
+ unsigned long min_limit,
+ unsigned long max_limit)
+{
+ sdp_result_e result1 = SDP_SUCCESS;
+ unsigned long value;
+ char* strtoul_end;
+
+ result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
+ if (result1 != SDP_SUCCESS) return result1;
+
+ errno = 0;
+ value = strtoul(*tok, &strtoul_end, 10);
+
+ if (errno
+ || (*tok == strtoul_end)
+ || (illegal_value != -1UL && value == illegal_value)
+ || (min_limit != -1UL && value < min_limit)
+ || (max_limit != -1UL && value > max_limit)) {
+ sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok);
+ return SDP_INVALID_PARAMETER;
+ }
+ *strtoul_result = value;
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ uint16_t i;
+ uint32_t mapword;
+ uint32_t bmap;
+ uint8_t low_val;
+ uint8_t high_val;
+ const char *ptr2;
+ const char *fmtp_ptr;
+ sdp_result_e result1 = SDP_SUCCESS;
+ sdp_result_e result2 = SDP_SUCCESS;
+ tinybool done = FALSE;
+ tinybool codec_info_found = FALSE;
+ sdp_fmtp_t *fmtp_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *src_ptr;
+ char *temp_ptr = NULL;
+ char *tok=NULL;
+ char *temp=NULL;
+ uint16_t custom_x=0;
+ uint16_t custom_y=0;
+ uint16_t custom_mpi=0;
+ uint16_t par_height=0;
+ uint16_t par_width=0;
+ uint16_t cpcf=0;
+ uint16_t iter=0;
+
+ ulong l_val = 0;
+ char* strtok_state;
+ unsigned long strtoul_result;
+ char* strtoul_end;
+
+ /* Find the payload type number. */
+ attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ sdp_attr_fmtp_no_value(sdp_p, "payload type");
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
+ fmtp_p->parameter_add = 1;
+ fmtp_p->flag = 0;
+
+ /*
+ * set default value of packetization mode and level-asymmetry-allowed. If
+ * remote sdp does not specify any value for these two parameters, then the
+ * default value will be assumed for remote sdp. If remote sdp does specify
+ * any value for these parameters, then default value will be overridden.
+ */
+ fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE;
+ fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE;
+
+ temp_ptr = cpr_strdup(ptr);
+ if (temp_ptr == NULL) {
+ return (SDP_FAILURE);
+ }
+ fmtp_ptr = src_ptr = temp_ptr;
+
+ src_ptr = temp_ptr;
+ while (!done) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
+ if (result1 == SDP_SUCCESS) {
+ if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
+ sdp_fmtp_codec_param[1].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
+ sdp_fmtp_codec_param_val[0].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexb_required = TRUE;
+ fmtp_p->annexb = TRUE;
+ } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
+ sdp_fmtp_codec_param_val[1].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexb_required = TRUE;
+ fmtp_p->annexb = FALSE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
+ sdp_fmtp_codec_param[0].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
+ sdp_fmtp_codec_param_val[0].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexa = TRUE;
+ fmtp_p->annexa_required = TRUE;
+ } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
+ sdp_fmtp_codec_param_val[1].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annexa = FALSE;
+ fmtp_p->annexa_required = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
+ sdp_fmtp_codec_param[2].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bitrate = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
+ sdp_fmtp_codec_param[41].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_MODE;
+ fmtp_p->mode = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
+ sdp_fmtp_codec_param[3].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->qcif = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
+ sdp_fmtp_codec_param[4].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
+ sdp_fmtp_codec_param[5].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxbr = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
+ sdp_fmtp_codec_param[6].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->sqcif = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
+ sdp_fmtp_codec_param[7].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif4 = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
+ sdp_fmtp_codec_param[8].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cif16 = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
+ sdp_fmtp_codec_param[9].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ temp=PL_strtok_r(tok, ",", &strtok_state);
+ iter++;
+ if (temp) {
+ iter=1;
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
+ custom_x = custom_y = custom_mpi = 0;
+ break;
+ }
+
+ if (iter == 1)
+ custom_x = (uint16_t) strtoul_result;
+ if (iter == 2)
+ custom_y = (uint16_t) strtoul_result;
+ if (iter == 3)
+ custom_mpi = (uint16_t) strtoul_result;
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ }
+
+ /* custom x,y and mpi values from tmp */
+ if (!custom_x || !custom_y || !custom_mpi) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->custom_x = custom_x;
+ fmtp_p->custom_y = custom_y;
+ fmtp_p->custom_mpi = custom_mpi;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
+ sdp_fmtp_codec_param[10].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ temp=PL_strtok_r(tok, ":", &strtok_state);
+ if (temp) {
+ iter=1;
+ /* get par width and par height for the aspect ratio */
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ par_width = par_height = 0;
+ break;
+ }
+
+ if (iter == 1)
+ par_width = (uint16_t) strtoul_result;
+ else
+ par_height = (uint16_t) strtoul_result;
+
+ temp=PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ }
+ if (!par_width || !par_height) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->par_width = par_width;
+ fmtp_p->par_height = par_height;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
+ sdp_fmtp_codec_param[11].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ temp=PL_strtok_r(tok, ".", &strtok_state);
+ if ( temp != NULL ) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ cpcf = 0;
+ } else {
+ cpcf = (uint16_t) strtoul_result;
+ }
+ }
+
+ if (!cpcf) {
+ sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cpcf = cpcf;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
+ sdp_fmtp_codec_param[12].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->bpp = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
+ sdp_fmtp_codec_param[13].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->hrd = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
+ sdp_fmtp_codec_param[14].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->profile = (short) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
+ sdp_fmtp_codec_param[15].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->level = (short) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
+ sdp_fmtp_codec_param[16].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->is_interlace = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
+ sdp_fmtp_codec_param[17].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
+ sdp_fmtp_codec_param[18].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
+ sdp_fmtp_codec_param[19].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, 2);
+ // this one is different for some reason. Most others don't increment
+ // the num_invalid_param field. (mjf)
+ if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->packetization_mode = (int16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
+ sdp_fmtp_codec_param[20].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->interleaving_depth = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
+ sdp_fmtp_codec_param[21].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_req = (uint32_t) l_val;
+ fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
+ sdp_fmtp_codec_param[22].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_don_diff = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
+ sdp_fmtp_codec_param[23].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->init_buf_time = (uint32_t) l_val;
+ fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
+ sdp_fmtp_codec_param[24].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_mbps = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
+ sdp_fmtp_codec_param[25].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_fs = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
+ sdp_fmtp_codec_param[26].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_cpb = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
+ sdp_fmtp_codec_param[27].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_dpb = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
+ sdp_fmtp_codec_param[28].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_br = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
+ sdp_fmtp_codec_param[29].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, 1);
+ fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS);
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
+ sdp_fmtp_codec_param[30].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->deint_buf_cap = (uint32_t) l_val;
+ fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
+ sdp_fmtp_codec_param[31].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val;
+ fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
+ codec_info_found = TRUE;
+ } else {
+ sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
+ sdp_fmtp_codec_param[32].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, 1);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->parameter_add = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
+ sdp_fmtp_codec_param[33].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_d = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
+ sdp_fmtp_codec_param[34].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_f = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
+ sdp_fmtp_codec_param[35].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_i = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
+ sdp_fmtp_codec_param[36].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_j = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
+ sdp_fmtp_codec_param[36].strlen) == 0) {
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_t = TRUE;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
+ sdp_fmtp_codec_param[38].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_k_val = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
+ sdp_fmtp_codec_param[39].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, USHRT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->annex_n_val = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
+ sdp_fmtp_codec_param[40].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->annex_p_val_picture_resize = 0;
+ fmtp_p->annex_p_val_warp = 0;
+ temp = PL_strtok_r(tok, ",", &strtok_state);
+ if (temp) {
+ iter=1;
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ break;
+ }
+
+ if (iter == 1)
+ fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result;
+ else if (iter == 2)
+ fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;
+
+ temp = PL_strtok_r(NULL, ",", &strtok_state);
+ iter++;
+ }
+ } else {
+ SDP_FREE(temp_ptr);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
+ sdp_fmtp_codec_param[42].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
+ sdp_fmtp_codec_param[43].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
+ sdp_fmtp_codec_param[44].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, 1);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->usedtx = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
+ sdp_fmtp_codec_param[45].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, 1);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->stereo = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
+ sdp_fmtp_codec_param[46].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, 1);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->useinbandfec = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
+ sdp_fmtp_codec_param[47].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok);
+ // this one is different for some reason. Most others don't increment
+ // the num_invalid_param field. (mjf)
+ if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
+ sdp_fmtp_codec_param[48].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp),
+ &tok, &strtoul_result, -1, -1, 1);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->cbr = (uint16_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
+ sdp_fmtp_codec_param[49].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->max_fr = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
+ sdp_fmtp_codec_param[50].strlen) == 0) {
+ result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp),
+ &tok, &strtoul_result, 0, -1, UINT_MAX);
+ if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
+
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+ fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
+ codec_info_found = TRUE;
+
+ } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
+ temp=PL_strtok_r(tmp, ";", &strtok_state);
+ if (temp) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
+ sdp_p->debug_str, fmtp_ptr, tmp);
+ }
+ while (temp != NULL) {
+ if (strchr(temp, 'D') !=NULL) {
+ attr_p->attr.fmtp.annex_d = TRUE;
+ }
+ if (strchr(temp, 'F') !=NULL) {
+ attr_p->attr.fmtp.annex_f = TRUE;
+ }
+ if (strchr(temp, 'I') !=NULL) {
+ attr_p->attr.fmtp.annex_i = TRUE;
+ }
+ if (strchr(temp, 'J') !=NULL) {
+ attr_p->attr.fmtp.annex_j = TRUE;
+ }
+ if (strchr(temp, 'T') !=NULL) {
+ attr_p->attr.fmtp.annex_t = TRUE;
+ }
+ temp=PL_strtok_r(NULL, ";", &strtok_state);
+ }
+ } /* if (temp) */
+ done = TRUE;
+ } else if (strchr(tmp, '/')) {
+ // XXX Note that because RFC 5109 so conveniently specified
+ // this fmtp with no param names, we hope that nothing else
+ // has a slash in the string because otherwise we won't know
+ // how to differentiate.
+ temp=PL_strtok_r(tmp, "/", &strtok_state);
+ if (temp) {
+ iter = 0;
+ while (temp != NULL) {
+ errno = 0;
+ strtoul_result = strtoul(temp, &strtoul_end, 10);
+
+ if (errno ||
+ temp == strtoul_end || strtoul_result > USHRT_MAX) {
+ temp = NULL;
+ continue;
+ }
+ fmtp_p->redundant_encodings[iter++] =
+ (uint8_t)strtoul_result;
+ temp=PL_strtok_r(NULL, "/", &strtok_state);
+ }
+ } /* if (temp) */
+ } else if (SDP_SUCCESS == sdp_verify_attr_fmtp_telephone_event(tmp)) {
+ // XXX Note that DTMF fmtp will fall into here:
+ // a=fmtp:101 0-15 (or 0-15,NN,NN etc)
+ sstrncpy(fmtp_p->dtmf_tones , tmp, sizeof(fmtp_p->dtmf_tones));
+ codec_info_found = TRUE;
+ } else {
+ // unknown parameter - eat chars until ';'
+ CSFLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__,
+ tmp);
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
+ &result1);
+ if (result1 != SDP_SUCCESS) {
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ // hmmm, no ; or spaces or tabs; continue on
+ }
+ }
+ }
+ if (*fmtp_ptr == '\n') {
+ // reached end of line, stop parsing
+ done = TRUE;
+ } else {
+ fmtp_ptr++;
+ }
+ } else {
+ done = TRUE;
+ }
+ } /* while - done loop*/
+
+ if (codec_info_found) {
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %u, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num,
+ attr_p->attr.fmtp.bitrate,
+ attr_p->attr.fmtp.mode,
+ attr_p->attr.fmtp.qcif,
+ attr_p->attr.fmtp.cif,
+ attr_p->attr.fmtp.maxbr,
+ attr_p->attr.fmtp.sqcif,
+ attr_p->attr.fmtp.cif4,
+ attr_p->attr.fmtp.cif16,
+ attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y,
+ attr_p->attr.fmtp.custom_mpi,
+ attr_p->attr.fmtp.par_width,
+ attr_p->attr.fmtp.par_height,
+ attr_p->attr.fmtp.cpcf,
+ attr_p->attr.fmtp.bpp,
+ attr_p->attr.fmtp.hrd
+ );
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num,
+ attr_p->attr.fmtp.profile,
+ attr_p->attr.fmtp.level,
+ attr_p->attr.fmtp.is_interlace ? "YES":"NO");
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%u max-don-diff=%u, init_buf-time=%u\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.profile_level_id,
+ attr_p->attr.fmtp.parameter_sets,
+ attr_p->attr.fmtp.packetization_mode,
+ attr_p->attr.fmtp.level_asymmetry_allowed,
+ attr_p->attr.fmtp.interleaving_depth,
+ attr_p->attr.fmtp.deint_buf_req,
+ attr_p->attr.fmtp.max_don_diff,
+ attr_p->attr.fmtp.init_buf_time
+ );
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%u, max-fs=%u, max-cpb=%u max-dpb=%u max-br=%u redundant-pic-cap=%d, deint-buf-cap=%u, max-rcmd-nalu-size=%u , parameter-add=%d\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.max_mbps,
+ attr_p->attr.fmtp.max_fs,
+ attr_p->attr.fmtp.max_cpb,
+ attr_p->attr.fmtp.max_dpb,
+ attr_p->attr.fmtp.max_br,
+ attr_p->attr.fmtp.redundant_pic_cap,
+ attr_p->attr.fmtp.deint_buf_cap,
+ attr_p->attr.fmtp.max_rcmd_nalu_size,
+ attr_p->attr.fmtp.parameter_add);
+
+ }
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
+ sdp_p->debug_str,
+ attr_p->attr.fmtp.annex_d,
+ attr_p->attr.fmtp.annex_f, attr_p->attr.fmtp.annex_i,
+ attr_p->attr.fmtp.annex_j, attr_p->attr.fmtp.annex_t,
+ attr_p->attr.fmtp.annex_k_val,
+ attr_p->attr.fmtp.annex_n_val,
+ attr_p->attr.fmtp.annex_p_val_picture_resize,
+ attr_p->attr.fmtp.annex_p_val_warp);
+
+ }
+ SDP_FREE(temp_ptr);
+ return (SDP_SUCCESS);
+ } else {
+ done = FALSE;
+ fmtp_ptr = src_ptr;
+ tmp[0] = '\0';
+ }
+
+ for (i=0; !done; i++) {
+ fmtp_p->fmtp_format = SDP_FMTP_NTE;
+ /* Look for comma separated events */
+ fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1);
+ if (result1 != SDP_SUCCESS) {
+ done = TRUE;
+ continue;
+ }
+ /* Now look for '-' separated range */
+ ptr2 = tmp;
+ low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
+ "- \t", &result1);
+ if (*ptr2 == '-') {
+ high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
+ "- \t", &result2);
+ } else {
+ high_val = low_val;
+ }
+
+ if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid named events specified for fmtp attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ for (i = low_val; i <= high_val; i++) {
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ fmtp_p->bmap[mapword] |= bmap;
+ }
+ if (high_val > fmtp_p->maxval) {
+ fmtp_p->maxval = high_val;
+ }
+ }
+
+ if (fmtp_p->maxval == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No named events specified for fmtp attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(temp_ptr);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.fmtp.payload_num);
+ }
+ SDP_FREE(temp_ptr);
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e
+sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs)
+{
+ uint16_t event_id;
+ uint32_t mask;
+ uint32_t mapword;
+ uint8_t min = 0;
+ uint8_t max = 0;
+ tinybool range_start = FALSE;
+ tinybool range_end = FALSE;
+ tinybool semicolon = FALSE;
+
+ switch (fmtp_p->fmtp_format) {
+ case SDP_FMTP_MODE:
+ sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
+ break;
+
+ case SDP_FMTP_CODEC_INFO:
+ FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate)
+
+ FMTP_BUILD_STRING(fmtp_p->annexa_required,
+ "annexa", (fmtp_p->annexa ? "yes" : "no"))
+
+ FMTP_BUILD_STRING(fmtp_p->annexb_required,
+ "annexb", (fmtp_p->annexa ? "yes" : "no"))
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->qcif > 0, "QCIF", fmtp_p->qcif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif > 0, "CIF", fmtp_p->cif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->maxbr > 0, "MAXBR", fmtp_p->maxbr)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->sqcif > 0, "SQCIF", fmtp_p->sqcif)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif4 > 0, "CIF4", fmtp_p->cif4)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cif16 > 0, "CIF16", fmtp_p->cif16)
+
+ if ((fmtp_p->custom_x > 0) && (fmtp_p->custom_y > 0) &&
+ (fmtp_p->custom_mpi > 0)) {
+ flex_string_sprintf(fs, "%sCUSTOM=%u,%u,%u",
+ semicolon ? ";" : "",
+ fmtp_p->custom_x,
+ fmtp_p->custom_y,
+ fmtp_p->custom_mpi);
+
+ semicolon = TRUE;
+ }
+
+ if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) {
+ flex_string_sprintf(fs, "%sPAR=%u:%u",
+ semicolon ? ";" : "",
+ fmtp_p->par_width,
+ fmtp_p->par_width);
+
+ semicolon = TRUE;
+ }
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cpcf > 0, "CPCF", fmtp_p->cpcf)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->bpp > 0, "BPP", fmtp_p->bpp)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->hrd > 0, "HRD", fmtp_p->hrd)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->profile >= 0, "PROFILE", fmtp_p->profile)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->level >= 0, "LEVEL", fmtp_p->level)
+
+ FMTP_BUILD_FLAG(fmtp_p->is_interlace, "INTERLACE")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_d, "D")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_f, "F")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_i, "I")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_j, "J")
+
+ FMTP_BUILD_FLAG(fmtp_p->annex_t, "T")
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->annex_k_val > 0,
+ "K", fmtp_p->annex_k_val)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->annex_n_val > 0,
+ "N", fmtp_p->annex_n_val)
+
+ if ((fmtp_p->annex_p_val_picture_resize > 0) &&
+ (fmtp_p->annex_p_val_warp > 0)) {
+ flex_string_sprintf(fs, "%sP=%d:%d",
+ semicolon ? ";" : "",
+ fmtp_p->annex_p_val_picture_resize,
+ fmtp_p->annex_p_val_warp);
+
+ semicolon = TRUE;
+ }
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->profile_level_id) > 0,
+ "profile-level-id", fmtp_p->profile_level_id)
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->parameter_sets) > 0,
+ "sprop-parameter-sets", fmtp_p->parameter_sets)
+
+ FMTP_BUILD_UNSIGNED(
+ fmtp_p->packetization_mode < SDP_MAX_PACKETIZATION_MODE_VALUE,
+ "packetization-mode", fmtp_p->packetization_mode)
+
+ FMTP_BUILD_UNSIGNED(
+ fmtp_p->level_asymmetry_allowed <=
+ SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE,
+ "level-asymmetry-allowed", fmtp_p->level_asymmetry_allowed)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->interleaving_depth > 0,
+ "sprop-interleaving-depth", fmtp_p->interleaving_depth)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_REQ_FLAG,
+ "sprop-deint-buf-req", fmtp_p->deint_buf_req)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_don_diff > 0,
+ "sprop-max-don-diff", fmtp_p->max_don_diff)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_INIT_BUF_TIME_FLAG,
+ "sprop-init-buf-time", fmtp_p->init_buf_time)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_mbps > 0,
+ "max-mbps", fmtp_p->max_mbps)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_fs > 0, "max-fs", fmtp_p->max_fs)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_fr > 0, "max-fr", fmtp_p->max_fr)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_cpb > 0, "max-cpb", fmtp_p->max_cpb)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_dpb > 0, "max-dpb", fmtp_p->max_dpb)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->max_br > 0, "max-br", fmtp_p->max_br)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->redundant_pic_cap > 0,
+ "redundant-pic-cap", fmtp_p->redundant_pic_cap)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_CAP_FLAG,
+ "deint-buf-cap", fmtp_p->deint_buf_cap)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_MAX_RCMD_NALU_SIZE_FLAG,
+ "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p->max_rcmd_nalu_size)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->parameter_add <= 1, "parameter-add",
+ fmtp_p->parameter_add)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->maxaveragebitrate > 0,
+ "maxaveragebitrate", fmtp_p->maxaveragebitrate)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->usedtx <= 1, "usedtx", fmtp_p->usedtx)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->stereo <= 1, "stereo", fmtp_p->stereo)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->useinbandfec <= 1,
+ "useinbandfec", fmtp_p->useinbandfec)
+
+ FMTP_BUILD_STRING(strlen(fmtp_p->maxcodedaudiobandwidth) > 0,
+ "maxcodedaudiobandwidth", fmtp_p->maxcodedaudiobandwidth)
+
+ FMTP_BUILD_UNSIGNED(fmtp_p->cbr <= 1, "cbr", fmtp_p->cbr)
+
+ break;
+
+ case SDP_FMTP_NTE:
+ default:
+ break;
+ }
+
+ for(event_id = 0, mapword = 0, mask = SDP_NE_BIT_0;
+ event_id <= fmtp_p->maxval;
+ event_id++, mapword = event_id/SDP_NE_BITS_PER_WORD ) {
+
+ if (event_id % SDP_NE_BITS_PER_WORD) {
+ mask <<= 1;
+ } else {
+ /* crossed a bitmap word boundary */
+ mask = SDP_NE_BIT_0;
+ if (!range_start && !range_end && !fmtp_p->bmap[mapword]) {
+ /* no events in this word, skip to the last event id
+ * in this bitmap word. */
+ event_id += SDP_NE_BITS_PER_WORD - 1;
+ continue;
+ }
+ }
+
+ if (fmtp_p->bmap[mapword] & mask) {
+ if (!range_start) {
+ range_start = TRUE;
+ min = max = (uint8_t)event_id;
+ } else {
+ max = (uint8_t)event_id;
+ }
+ range_end = (max == fmtp_p->maxval);
+ } else {
+ /* If we were in the middle of a range, then we've hit the
+ * end. If we weren't, there is no end to hit. */
+ range_end = range_start;
+ }
+
+ /* If this is the end of the range, print it to the string. */
+ if (range_end) {
+ range_start = range_end = FALSE;
+
+ flex_string_sprintf(fs, "%u", min);
+
+ if (min != max) {
+ flex_string_sprintf(fs, "-%u", max);
+ }
+
+ if (max != fmtp_p->maxval) {
+ flex_string_append(fs, ",");
+ }
+ }
+ }
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ sdp_fmtp_t *fmtp_p;
+ sdp_result_e result;
+
+ flex_string_sprintf(fs, "a=%s:%u ",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.fmtp.payload_num);
+
+ fmtp_p = &(attr_p->attr.fmtp);
+
+ result = sdp_build_attr_fmtp_params(sdp_p, fmtp_p, fs);
+
+ if (result != SDP_SUCCESS) {
+ return result;
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result = SDP_SUCCESS;
+ char tmp[SDP_MAX_STRING_LEN];
+ uint32_t streams;
+
+ /* Find the payload type number. */
+ attr_p->attr.sctpmap.port = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: no sctpmap port number",
+ sdp_p->debug_str);
+ return SDP_INVALID_PARAMETER;
+ }
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No sctpmap protocol specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ sstrncpy(attr_p->attr.sctpmap.protocol, tmp,
+ sizeof (attr_p->attr.sctpmap.protocol));
+
+ streams = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No sctpmap streams specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ attr_p->attr.sctpmap.streams = streams;
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%u %s %u\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.sctpmap.port,
+ attr_p->attr.sctpmap.protocol,
+ attr_p->attr.sctpmap.streams);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ /* No parameters to parse. */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the strength tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos strength tag specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.qos.strength = SDP_QOS_STRENGTH_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
+ sdp_qos_strength[i].strlen) == 0) {
+ attr_p->attr.qos.strength = (sdp_qos_strength_e)i;
+ }
+ }
+ if (attr_p->attr.qos.strength == SDP_QOS_STRENGTH_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS strength tag unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.qos.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.qos.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.qos.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* See if confirm was specified. Defaults to FALSE. */
+ attr_p->attr.qos.confirm = FALSE;
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
+ attr_p->attr.qos.confirm = TRUE;
+ }
+ if (attr_p->attr.qos.confirm == FALSE) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS confirm parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, strength %s, direction %s, confirm %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_direction_name(attr_p->attr.qos.direction),
+ (attr_p->attr.qos.confirm ? "set" : "not set"));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s%s\r\n", sdp_attr[attr_p->type].name,
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_direction_name(attr_p->attr.qos.direction),
+ attr_p->attr.qos.confirm ? " confirm" : "");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No curr attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.type = SDP_CURR_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_curr_type[i].name,
+ sdp_curr_type[i].strlen) == 0) {
+ attr_p->attr.curr.type = (sdp_curr_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.curr.type != SDP_CURR_QOS_TYPE) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unknown curr type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No curr attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.curr.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.curr.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.curr.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.curr.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_curr_type_name(attr_p->attr.curr.type),
+ sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.curr.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_curr_type_name(attr_p->attr.curr.type),
+ sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.curr.direction));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No des attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.type = SDP_DES_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_des_type[i].name,
+ sdp_des_type[i].strlen) == 0) {
+ attr_p->attr.des.type = (sdp_des_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.des.type != SDP_DES_QOS_TYPE) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unknown conf type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the strength tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos strength tag specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.strength = SDP_QOS_STRENGTH_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
+ sdp_qos_strength[i].strlen) == 0) {
+ attr_p->attr.des.strength = (sdp_qos_strength_e)i;
+ }
+ }
+ if (attr_p->attr.des.strength == SDP_QOS_STRENGTH_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS strength tag unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No des attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.des.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.des.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.des.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.des.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_des_type_name(attr_p->attr.des.type),
+ sdp_get_qos_strength_name(attr_p->attr.qos.strength),
+ sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.des.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+
+sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_curr_type_name((sdp_curr_type_e)attr_p->attr.des.type),
+ sdp_get_qos_strength_name(attr_p->attr.des.strength),
+ sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.des.direction));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the curr type tag. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No conf attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.type = SDP_CONF_UNKNOWN_TYPE;
+ for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_conf_type[i].name,
+ sdp_conf_type[i].strlen) == 0) {
+ attr_p->attr.conf.type = (sdp_conf_type_e)i;
+ }
+ }
+
+ if (attr_p->attr.conf.type != SDP_CONF_QOS_TYPE) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unknown conf type.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Check qos status type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No conf attr type specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
+ sdp_qos_status_type[i].strlen) == 0) {
+ attr_p->attr.conf.status_type = (sdp_qos_status_types_e)i;
+ }
+ }
+
+
+ /* Find the qos direction. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No qos direction specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.conf.direction = SDP_QOS_DIR_UNKNOWN;
+ for (i=0; i < SDP_MAX_QOS_DIR; i++) {
+ if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
+ sdp_qos_direction[i].strlen) == 0) {
+ attr_p->attr.conf.direction = (sdp_qos_dir_e)i;
+ }
+ }
+ if (attr_p->attr.conf.direction == SDP_QOS_DIR_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: QOS direction unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_conf_type_name(attr_p->attr.conf.type),
+ sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.conf.direction));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_conf_type_name(attr_p->attr.conf.type),
+ sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
+ sdp_get_qos_direction_name(attr_p->attr.conf.direction));
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * Parse a rtpmap or a sprtmap. Both formats use the same structure
+ * the only difference being the keyword "rtpmap" vs "sprtmap". The
+ * rtpmap field in the sdp_attr_t is used to store both mappings.
+ */
+sdp_result_e sdp_parse_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.transport_map.payload_num = 0;
+ attr_p->attr.transport_map.encname[0] = '\0';
+ attr_p->attr.transport_map.clockrate = 0;
+ attr_p->attr.transport_map.num_chan = 1;
+
+ /* Find the payload type number. */
+ attr_p->attr.transport_map.payload_num =
+ (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid payload type specified for %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the encoding name. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.transport_map.encname,
+ sizeof(attr_p->attr.transport_map.encname), "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No encoding name specified in %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the clockrate. */
+ attr_p->attr.transport_map.clockrate =
+ sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No clockrate specified for "
+ "%s attribute, set to default of 8000.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ attr_p->attr.transport_map.clockrate = 8000;
+ }
+
+ /* Find the number of channels, if specified. This is optional. */
+ if (*ptr == '/') {
+ /* If a '/' exists, expect something valid beyond it. */
+ attr_p->attr.transport_map.num_chan =
+ (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid number of channels parameter"
+ " for rtpmap attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, payload type %u, encoding name %s, "
+ "clockrate %u", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate);
+ if (attr_p->attr.transport_map.num_chan != 1) {
+ SDP_PRINT("/%u", attr_p->attr.transport_map.num_chan);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * Build a rtpmap or a sprtmap. Both formats use the same structure
+ * the only difference being the keyword "rtpmap" vs "sprtmap". The
+ * rtpmap field in the sdp_attr_t is used for both mappings.
+ */
+sdp_result_e sdp_build_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.transport_map.num_chan == 1) {
+ flex_string_sprintf(fs, "a=%s:%u %s/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate);
+ } else {
+ flex_string_sprintf(fs, "a=%s:%u %s/%u/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.transport_map.payload_num,
+ attr_p->attr.transport_map.encname,
+ attr_p->attr.transport_map.clockrate,
+ attr_p->attr.transport_map.num_chan);
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ char *slash_ptr;
+ sdp_result_e result;
+ tinybool type_found = FALSE;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the subnet network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No network type specified in subnet attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.subnet.nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.subnet.nettype = (sdp_nettype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.subnet.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Subnet network type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the subnet address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No address type specified in subnet attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.subnet.addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.subnet.addrtype = (sdp_addrtype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.subnet.addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Subnet address type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the subnet address. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.subnet.addr,
+ sizeof(attr_p->attr.subnet.addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No subnet address specified in "
+ "subnet attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ slash_ptr = sdp_findchar(attr_p->attr.subnet.addr, "/");
+ if (*slash_ptr == '/') {
+ *slash_ptr++ = '\0';
+ /* If the '/' exists, expect a valid prefix to follow. */
+ attr_p->attr.subnet.prefix = sdp_getnextnumtok(slash_ptr,
+ (const char **)&slash_ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid subnet prefix specified in "
+ "subnet attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ } else {
+ attr_p->attr.subnet.prefix = SDP_INVALID_VALUE;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr);
+ if (attr_p->attr.subnet.prefix != SDP_INVALID_VALUE) {
+ SDP_PRINT("/%u", (ushort)attr_p->attr.subnet.prefix);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.subnet.prefix == SDP_INVALID_VALUE) {
+ flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr);
+ } else {
+ flex_string_sprintf(fs, "a=%s:%s %s %s/%u\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_network_name(attr_p->attr.subnet.nettype),
+ sdp_get_address_name(attr_p->attr.subnet.addrtype),
+ attr_p->attr.subnet.addr,
+ (ushort)attr_p->attr.subnet.prefix);
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the rate mgmt. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No t38 rate management specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.t38ratemgmt = SDP_T38_UNKNOWN_RATE;
+ for (i=0; i < SDP_T38_MAX_RATES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_t38_rate[i].name,
+ sdp_t38_rate[i].strlen) == 0) {
+ attr_p->attr.t38ratemgmt = (sdp_t38_ratemgmt_e)i;
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find the udpec. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No t38 udpEC specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.t38udpec = SDP_T38_UDPEC_UNKNOWN;
+ for (i=0; i < SDP_T38_MAX_UDPEC; i++) {
+ if (cpr_strncasecmp(tmp, sdp_t38_udpec[i].name,
+ sdp_t38_udpec[i].strlen) == 0) {
+ attr_p->attr.t38udpec = (sdp_t38_udpec_e)i;
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ uint16_t i;
+ sdp_result_e result;
+
+ for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
+ attr_p->attr.pccodec.payload_type[i] = (ushort)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.pccodec.num_payloads++;
+ }
+
+ if (attr_p->attr.pccodec.num_payloads == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No payloads specified for %s attr.",
+ sdp_p->debug_str, sdp_attr[attr_p->type].name);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, num payloads %u, payloads: ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ attr_p->attr.pccodec.num_payloads);
+ for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
+ SDP_PRINT("%u ", attr_p->attr.pccodec.payload_type[i]);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s: ", sdp_attr[attr_p->type].name);
+
+ for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
+ flex_string_sprintf(fs, "%u ", attr_p->attr.pccodec.payload_type[i]);
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ uint16_t i;
+ sdp_result_e result;
+ sdp_mca_t *cap_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Set the capability pointer to NULL for now in case we encounter
+ * an error in parsing.
+ */
+ attr_p->attr.cap_p = NULL;
+ /* Set the capability valid flag to FALSE in case we encounter an
+ * error. If we do, we don't want to process any X-cpar/cpar attributes
+ * from this point until we process the next valid X-cap/cdsc attr. */
+ sdp_p->cap_valid = FALSE;
+
+ /* Allocate resource for new capability. Note that the capability
+ * uses the same structure used for media lines.
+ */
+ cap_p = sdp_alloc_mca(sdp_p->parse_line);
+ if (cap_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Find the capability number. We don't need to store this since we
+ * calculate it for ourselves as we need to. But it must be specified. */
+ (void)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Capability not specified for %s, "
+ "unable to parse.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the media type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No media type specified for %s attribute, "
+ "unable to parse.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p->media = SDP_MEDIA_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_media[i].name, sdp_media[i].strlen) == 0) {
+ cap_p->media = (sdp_media_e)i;
+ break;
+ }
+ }
+ if (cap_p->media == SDP_MEDIA_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Media type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the transport protocol type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No transport protocol type specified, "
+ "unable to parse.", sdp_p->debug_str);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p->transport = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ cap_p->transport = (sdp_transport_e)i;
+ break;
+ }
+ }
+ if (cap_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Transport protocol type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find payload formats. AAL2 X-cap lines allow multiple
+ * transport/profile types per line, so these are handled differently.
+ */
+ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Capability processing is not currently defined for AAL2 types
+ * with multiple profiles. We don't process. */
+ sdp_parse_error(sdp_p,
+ "%s Warning: AAL2 profiles unsupported with "
+ "%s attributes.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* Transport is a non-AAL2 type. Parse payloads normally. */
+ sdp_parse_payload_types(sdp_p, cap_p, ptr);
+ if (cap_p->num_payloads == 0) {
+ SDP_FREE(cap_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ attr_p->attr.cap_p = cap_p;
+ /*
+ * This capability attr is valid. We can now handle X-cpar or
+ * cpar attrs.
+ */
+ sdp_p->cap_valid = TRUE;
+ sdp_p->last_cap_inst++;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed %s media type %s, Transport %s, "
+ "Num payloads %u", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_media_name(cap_p->media),
+ sdp_get_transport_name(cap_p->transport),
+ cap_p->num_payloads);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ uint16_t i, j;
+ sdp_mca_t *cap_p;
+ sdp_media_profiles_t *profile_p;
+
+ /* Get a pointer to the capability structure. */
+ cap_p = attr_p->attr.cap_p;
+
+ if (cap_p == NULL) {
+ CSFLogError(logTag, "%s Invalid %s attribute, unable to build.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ /* Return success so build won't fail. */
+ return (SDP_SUCCESS);
+ }
+
+ /* Validate params for this capability line */
+ if ((cap_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (cap_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
+ CSFLogDebug(logTag, logTag, "%s Media or transport type invalid for %s "
+ "attribute, unable to build.", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ /* Return success so build won't fail. */
+ return (SDP_SUCCESS);
+ }
+
+ flex_string_sprintf(fs, "a=%s: %u %s ", sdp_attr[attr_p->type].name,
+ sdp_p->cur_cap_num, sdp_get_media_name(cap_p->media));
+
+ /* If the X-cap line has AAL2 profiles, build them differently. */
+ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ profile_p = cap_p->media_profiles_p;
+ for (i=0; i < profile_p->num_profiles; i++) {
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(profile_p->profile[i]));
+
+ for (j=0; j < profile_p->num_payloads[i]; j++) {
+ flex_string_sprintf(fs, " %u",
+ profile_p->payload_type[i][j]);
+ }
+ flex_string_append(fs, " ");
+ }
+
+ flex_string_append(fs, "\r\n");
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return SDP_SUCCESS;
+ }
+
+ /* Build the transport name */
+ flex_string_sprintf(fs, "%s", sdp_get_transport_name(cap_p->transport));
+
+ /* Build the format lists */
+ for (i=0; i < cap_p->num_payloads; i++) {
+ if (cap_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
+ flex_string_sprintf(fs, " %s",
+ sdp_get_payload_name((sdp_payload_e)cap_p->payload_type[i]));
+ } else {
+ flex_string_sprintf(fs, " %u", cap_p->payload_type[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ /* Increment the current capability number for the next X-cap/cdsc attr. */
+ sdp_p->cur_cap_num += cap_p->num_payloads;
+ sdp_p->last_cap_type = attr_p->type;
+
+ /* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */
+ return sdp_build_attr_cpar(sdp_p, cap_p->media_attrs_p, fs);
+}
+
+
+sdp_result_e sdp_parse_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ uint16_t i;
+ sdp_result_e result;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cap_attr_p = NULL;
+ sdp_attr_t *prev_attr_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Make sure we've processed a valid X-cap/cdsc attr prior to this and
+ * if so, get the cap pointer. */
+ if (sdp_p->cap_valid == TRUE) {
+ sdp_attr_e cap_type;
+
+ if (attr_p->type == SDP_ATTR_CPAR) {
+ cap_type = SDP_ATTR_CDSC;
+ } else {
+ /* Default to X-CAP for everything else */
+ cap_type = SDP_ATTR_X_CAP;
+ }
+
+ if (sdp_p->mca_count == 0) {
+ cap_attr_p = sdp_find_attr(sdp_p, SDP_SESSION_LEVEL, 0,
+ cap_type, sdp_p->last_cap_inst);
+ } else {
+ cap_attr_p = sdp_find_attr(sdp_p, sdp_p->mca_count, 0,
+ cap_type, sdp_p->last_cap_inst);
+ }
+ }
+ if ((cap_attr_p == NULL) || (cap_attr_p->attr.cap_p == NULL)) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: %s attribute specified with no "
+ "prior %s attribute", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ (attr_p->type == SDP_ATTR_CPAR)?
+ (sdp_get_attr_name(SDP_ATTR_CDSC)) :
+ (sdp_get_attr_name(SDP_ATTR_X_CAP)) );
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /*
+ * Ensure there is no mixed syntax like CDSC followed by X-CPAR
+ * or X-CAP followed by CPAR.
+ */
+ if (((cap_attr_p->type == SDP_ATTR_CDSC) &&
+ (attr_p->type == SDP_ATTR_X_CPAR)) ||
+ ( (cap_attr_p->type == SDP_ATTR_X_CAP) &&
+ (attr_p->type == SDP_ATTR_CPAR)) ) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: %s attribute inconsistent with "
+ "prior %s attribute", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_attr_name(cap_attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = cap_attr_p->attr.cap_p;
+
+ /* a= is the only token we handle in an X-cpar/cpar attribute. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "= \t", &result);
+
+ if ((result != SDP_SUCCESS) || (tmp[0] != 'a') || (tmp[1] != '\0')) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid token type (%s) in %s "
+ "attribute, unable to parse", sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ if (*ptr == '=') {
+ ptr++;
+ }
+
+ /* Find the attribute type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ if (ptr[0] == ':') {
+ /* Skip the ':' char for parsing attribute parameters. */
+ ptr++;
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No attribute type specified for %s attribute, unable to parse.",
+ sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Reset the type of the attribute from X-cpar/cpar to whatever the
+ * specified type is. */
+ attr_p->type = SDP_ATTR_INVALID;
+ attr_p->next_p = NULL;
+ for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
+ attr_p->type = (sdp_attr_e)i;
+ }
+ }
+ if (attr_p->type == SDP_ATTR_INVALID) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
+ sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* We don't allow recursion with the capability attributes. */
+ if ((attr_p->type == SDP_ATTR_X_SQN) ||
+ (attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_X_CPAR) ||
+ (attr_p->type == SDP_ATTR_SQN) ||
+ (attr_p->type == SDP_ATTR_CDSC) ||
+ (attr_p->type == SDP_ATTR_CPAR)) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid attribute (%s) for %s"
+ " attribute, unable to parse.", sdp_p->debug_str, tmp,
+ sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Parse the attribute. */
+ result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
+ if (result != SDP_SUCCESS) {
+ return (result);
+ }
+
+ /* Hook the attribute into the capability structure. */
+ if (cap_p->media_attrs_p == NULL) {
+ cap_p->media_attrs_p = attr_p;
+ } else {
+ for (prev_attr_p = cap_p->media_attrs_p;
+ prev_attr_p->next_p != NULL;
+ prev_attr_p = prev_attr_p->next_p) {
+ ; /* Empty for */
+ }
+ prev_attr_p->next_p = attr_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ sdp_result_e result;
+ const char *cpar_name;
+
+ /* Determine whether to use cpar or X-cpar */
+ if (sdp_p->last_cap_type == SDP_ATTR_CDSC) {
+ cpar_name = sdp_get_attr_name(SDP_ATTR_CPAR);
+ } else {
+ /*
+ * Default to X-CPAR if anything else. This is the backward
+ * compatible value.
+ */
+ cpar_name = sdp_get_attr_name(SDP_ATTR_X_CPAR);
+ }
+
+ while (attr_p != NULL) {
+ if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
+ CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
+ sdp_p->debug_str, (unsigned)attr_p->type);
+ } else {
+ flex_string_sprintf(fs, "a=%s: ", cpar_name);
+
+ result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
+
+ if (result == SDP_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built %s a=%s attribute line",
+ sdp_p->debug_str, cpar_name,
+ sdp_get_attr_name(attr_p->type));
+ }
+ }
+ }
+ attr_p = attr_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char nettype[SDP_MAX_STRING_LEN];
+ sdp_rtcp_t *rtcp_p = &(attr_p->attr.rtcp);
+ int enum_raw;
+
+ memset(rtcp_p, 0, sizeof(sdp_rtcp_t));
+
+ rtcp_p->port = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse port for rtcp attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+
+ return SDP_INVALID_PARAMETER;
+ }
+
+ /* The rest is optional, although it is all-or-nothing */
+ (void)sdp_getnextstrtok(ptr, nettype, sizeof(nettype), " \t", &result);
+ if (result == SDP_EMPTY_TOKEN) {
+ /* Nothing after the port */
+ return SDP_SUCCESS;
+ }
+
+ enum_raw = find_token_enum("Nettype", sdp_p, &ptr, sdp_nettype,
+ SDP_MAX_NETWORK_TYPES, SDP_NT_UNSUPPORTED);
+ if (enum_raw == -1) {
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_p->nettype = (sdp_nettype_e)enum_raw;
+
+ enum_raw = find_token_enum("Addrtype", sdp_p, &ptr, sdp_addrtype,
+ SDP_MAX_ADDR_TYPES, SDP_AT_UNSUPPORTED);
+ if (enum_raw == -1) {
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_p->addrtype = (sdp_addrtype_e)enum_raw;
+
+ ptr = sdp_getnextstrtok(ptr, rtcp_p->addr, sizeof(rtcp_p->addr), " \t",
+ &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse addr for rtcp attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+
+ return SDP_INVALID_PARAMETER;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ /* We should not be serializing SDP anyway, but we need this function until
+ * Bug 1112737 is resolved. */
+ return SDP_FAILURE;
+}
+
+sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+ /*Default confirm to FALSE. */
+ attr_p->attr.rtr.confirm = FALSE;
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS){ // No confirm tag specified is not an error
+ return (SDP_SUCCESS);
+ } else {
+ /* See if confirm was specified. Defaults to FALSE. */
+ if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
+ attr_p->attr.rtr.confirm = TRUE;
+ }
+ if (attr_p->attr.rtr.confirm == FALSE) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: RTR confirm parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ tmp);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.rtr.confirm ? ":confirm" : "");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ tinybool type_found = FALSE;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_PASSIVE;
+ attr_p->attr.comediadir.conn_info_present = FALSE;
+ attr_p->attr.comediadir.conn_info.nettype = SDP_NT_INVALID;
+ attr_p->attr.comediadir.src_port = 0;
+
+ /* Find the media direction role. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No role parameter specified for "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIADIR_ROLES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_mediadir_role[i].name,
+ sdp_mediadir_role[i].strlen) == 0) {
+ type_found = TRUE;
+ attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i;
+ break;
+ }
+ }
+ if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid role type specified for "
+ "comediadir attribute (%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* If the role is passive, we don't expect any more params. */
+ if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_PASSIVE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, passive",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ }
+ return (SDP_SUCCESS);
+ }
+
+ /* Find the connection information if present */
+ /* parse to get the nettype */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No network type specified in comediadir "
+ "attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SUCCESS); /* as the optional parameters are not there */
+ }
+ attr_p->attr.comediadir.conn_info.nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.comediadir.conn_info.nettype = (sdp_nettype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.comediadir.conn_info.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: ConnInfo in Comediadir: network type "
+ "unsupported (%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the comedia address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No address type specified in comediadir"
+ " attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+ attr_p->attr.comediadir.conn_info.addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ type_found = TRUE;
+ }
+ if (type_found == TRUE) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.comediadir.conn_info.addrtype = (sdp_addrtype_e)i;
+ }
+ type_found = FALSE;
+ }
+ }
+ if (attr_p->attr.comediadir.conn_info.addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Conninfo address type unsupported "
+ "(%s).", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the conninfo address. */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.comediadir.conn_info.conn_addr,
+ sizeof(attr_p->attr.comediadir.conn_info.conn_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No conninfo address specified in "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ /* Find the src port info , if any */
+ attr_p->attr.comediadir.src_port = sdp_getnextnumtok(ptr, &ptr, " \t",
+ &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No src port specified in "
+ "comediadir attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s "
+ "srcport %u ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ sdp_get_network_name(attr_p->attr.comediadir.conn_info.nettype),
+ sdp_get_address_name(attr_p->attr.comediadir.conn_info.addrtype),
+ attr_p->attr.comediadir.conn_info.conn_addr,
+ (unsigned int)attr_p->attr.comediadir.src_port);
+ }
+
+ if (sdp_p->conf_p->num_invalid_param > 0) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e
+sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_get_mediadir_role_name(attr_p->attr.comediadir.role));
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ /* Find silenceSuppEnable */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No silenceSupp enable value specified, parse failed.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (cpr_strncasecmp(tmp, "on", sizeof("on")) == 0) {
+ attr_p->attr.silencesupp.enabled = TRUE;
+ } else if (cpr_strncasecmp(tmp, "off", sizeof("off")) == 0) {
+ attr_p->attr.silencesupp.enabled = FALSE;
+ } else if (cpr_strncasecmp(tmp, "-", sizeof("-")) == 0) {
+ attr_p->attr.silencesupp.enabled = FALSE;
+ } else {
+ sdp_parse_error(sdp_p,
+ "%s Warning: silenceSuppEnable parameter invalid (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find silenceTimer -- uint16_t or "-" */
+
+ attr_p->attr.silencesupp.timer =
+ (uint16_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
+ &attr_p->attr.silencesupp.timer_null,
+ &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid timer value specified for "
+ "silenceSupp attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find suppPref */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No silenceSupp pref specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.silencesupp.pref = SDP_SILENCESUPP_PREF_UNKNOWN;
+ for (i=0; i < SDP_MAX_SILENCESUPP_PREF; i++) {
+ if (cpr_strncasecmp(tmp, sdp_silencesupp_pref[i].name,
+ sdp_silencesupp_pref[i].strlen) == 0) {
+ attr_p->attr.silencesupp.pref = (sdp_silencesupp_pref_e)i;
+ }
+ }
+ if (attr_p->attr.silencesupp.pref == SDP_SILENCESUPP_PREF_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: silenceSupp pref unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find sidUse */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No silenceSupp sidUse specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.silencesupp.siduse = SDP_SILENCESUPP_SIDUSE_UNKNOWN;
+ for (i=0; i < SDP_MAX_SILENCESUPP_SIDUSE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_silencesupp_siduse[i].name,
+ sdp_silencesupp_siduse[i].strlen) == 0) {
+ attr_p->attr.silencesupp.siduse = (sdp_silencesupp_siduse_e)i;
+ }
+ }
+ if (attr_p->attr.silencesupp.siduse == SDP_SILENCESUPP_SIDUSE_UNKNOWN) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: silenceSupp sidUse unrecognized (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find fxnslevel -- uint8_t or "-" */
+ attr_p->attr.silencesupp.fxnslevel =
+ (uint8_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
+ &attr_p->attr.silencesupp.fxnslevel_null,
+ &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid fxnslevel value specified for "
+ "silenceSupp attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, enabled %s",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ (attr_p->attr.silencesupp.enabled ? "on" : "off"));
+ if (attr_p->attr.silencesupp.timer_null) {
+ SDP_PRINT(" timer=-");
+ } else {
+ SDP_PRINT(" timer=%u,", attr_p->attr.silencesupp.timer);
+ }
+ SDP_PRINT(" pref=%s, siduse=%s,",
+ sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
+ sdp_get_silencesupp_siduse_name(
+ attr_p->attr.silencesupp.siduse));
+ if (attr_p->attr.silencesupp.fxnslevel_null) {
+ SDP_PRINT(" fxnslevel=-");
+ } else {
+ SDP_PRINT(" fxnslevel=%u,", attr_p->attr.silencesupp.fxnslevel);
+ }
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ char temp_timer_string[11];
+ char temp_fxnslevel_string[11];
+
+ if (attr_p->attr.silencesupp.timer_null) {
+ snprintf(temp_timer_string, sizeof(temp_timer_string), "-");
+ } else {
+ snprintf(temp_timer_string, sizeof(temp_timer_string), "%u", attr_p->attr.silencesupp.timer);
+ }
+
+ if (attr_p->attr.silencesupp.fxnslevel_null) {
+ snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "-");
+ } else {
+ snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "%u", attr_p->attr.silencesupp.fxnslevel);
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s %s\r\n",
+ sdp_attr[attr_p->type].name,
+ (attr_p->attr.silencesupp.enabled ? "on" : "off"),
+ temp_timer_string,
+ sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
+ sdp_get_silencesupp_siduse_name(attr_p->attr.silencesupp.siduse),
+ temp_fxnslevel_string);
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_context_crypto_suite
+ *
+ * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the
+ * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores
+ * pointer to the next crypto parameter in tmp_ptr
+ */
+tinybool sdp_parse_context_crypto_suite(char * str, sdp_attr_t *attr_p, sdp_t *sdp_p) {
+ /*
+ * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the <crypto-suite>
+ * AES_CM_128_HMAC_SHA1_80
+ * AES_CM_128_HMAC_SHA1_32
+ * F8_128_HMAC_SHA1_80
+ */
+
+ int i;
+
+ /* Check crypto suites */
+ for(i=0; i<SDP_SRTP_MAX_NUM_CRYPTO_SUITES; i++) {
+ if (!cpr_strcasecmp(sdp_srtp_crypto_suite_array[i].crypto_suite_str, str)) {
+ attr_p->attr.srtp_context.suite = sdp_srtp_crypto_suite_array[i].crypto_suite_val;
+ attr_p->attr.srtp_context.master_key_size_bytes =
+ sdp_srtp_crypto_suite_array[i].key_size_bytes;
+ attr_p->attr.srtp_context.master_salt_size_bytes =
+ sdp_srtp_crypto_suite_array[i].salt_size_bytes;
+ return TRUE; /* There is a succesful match so exit */
+ }
+ }
+ /* couldn't find a matching crypto suite */
+ sdp_parse_error(sdp_p,
+ "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
+ sdp_p->debug_str, str);
+
+ return FALSE;
+}
+
+
+sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+#define MAX_BASE64_ENCODE_SIZE_BYTES 60
+ int output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
+ int key_size = attr_p->attr.srtp_context.master_key_size_bytes;
+ int salt_size = attr_p->attr.srtp_context.master_salt_size_bytes;
+ unsigned char base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES];
+ unsigned char base64_encoded_input[MAX_BASE64_ENCODE_SIZE_BYTES];
+ base64_result_t status;
+
+ output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
+
+ /* Append master and salt keys */
+ memcpy(base64_encoded_input,
+ attr_p->attr.srtp_context.master_key,
+ key_size );
+ memcpy(base64_encoded_input + key_size,
+ attr_p->attr.srtp_context.master_salt,
+ salt_size );
+
+ if ((status = base64_encode(base64_encoded_input, key_size + salt_size,
+ base64_encoded_data, &output_len)) != BASE64_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ }
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ *(base64_encoded_data + output_len) = '\0';
+
+ flex_string_sprintf(fs, "a=%s:%s inline:%s||\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data);
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_parse_attr_mptime
+ * This function parses the a=mptime sdp line. This parameter consists of
+ * one or more numbers or hyphens ("-"). The first parameter must be a
+ * number. The number of parameters must match the number of formats specified
+ * on the m= line. This function is liberal in that it does not match against
+ * the m= line or require a number for the first parameter.
+ */
+sdp_result_e sdp_parse_attr_mptime (
+ sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ uint16_t i; /* loop counter for parameters */
+ sdp_result_e result; /* value returned by this function */
+ tinybool null_ind; /* true if a parameter is "-" */
+
+ /*
+ * Scan the input line up to the maximum number of parameters supported.
+ * Look for numbers or hyphens and store the resulting values. Hyphens
+ * are stored as zeros.
+ */
+ for (i=0; i<SDP_MAX_PAYLOAD_TYPES; i++) {
+ attr_p->attr.mptime.intervals[i] =
+ (ushort)sdp_getnextnumtok_or_null(ptr,&ptr," \t",&null_ind,&result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.mptime.num_intervals++;
+ }
+
+ /*
+ * At least one parameter must be supplied. If not, return an error
+ * and optionally log the failure.
+ */
+ if (attr_p->attr.mptime.num_intervals == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No intervals specified for %s attr.",
+ sdp_p->debug_str, sdp_attr[attr_p->type].name);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /*
+ * Here is some debugging code that helps us track what data
+ * is received and parsed.
+ */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
+ attr_p->attr.mptime.num_intervals);
+ for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
+ SDP_PRINT("%u ", attr_p->attr.mptime.intervals[i]);
+ }
+ }
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * sdp_build_attr_mptime
+ * This function builds the a=mptime sdp line. It reads the selected attribute
+ * from the sdp structure. Parameters with a value of zero are replaced by
+ * hyphens.
+ */
+sdp_result_e sdp_build_attr_mptime (
+ sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
+
+ /*
+ * Run the list of mptime parameter values and write each one
+ * to the sdp line. Replace zeros with hyphens.
+ */
+ for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
+ if (i > 0) {
+ flex_string_append(fs, " ");
+ }
+
+ if (attr_p->attr.mptime.intervals[i] == 0) {
+ flex_string_append(fs, "-");
+ } else {
+ flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+
+
+sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_sidin[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-sidin value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidin,
+ sizeof(attr_p->attr.stream_data.x_sidin), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No Stream Id incoming specified for X-sidin attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_sidin);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_sidin);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_sidout[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-sidout value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidout,
+ sizeof(attr_p->attr.stream_data.x_sidout), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No Stream Id outgoing specified for X-sidout attribute.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_sidout);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_sidout);
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ attr_p->attr.stream_data.x_confid[0] = '\0';
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the X-confid value */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_confid,
+ sizeof(attr_p->attr.stream_data.x_confid), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No Conf Id incoming specified for "
+ "X-confid attribute.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.stream_data.x_confid);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (strlen(attr_p->attr.stream_data.x_confid) <= 0) {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n",
+ sdp_p->debug_str);
+ }
+
+ return SDP_INVALID_PARAMETER;
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.stream_data.x_confid);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char tmp[64];
+ int i=0;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ /* Find the a=group:<attrib> <id1> < id2> ... values */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No group attribute value specified for "
+ "a=group line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.stream_data.group_attr = SDP_GROUP_ATTR_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_GROUP_ATTR_VAL; i++) {
+ if (cpr_strncasecmp(tmp, sdp_group_attr_val[i].name,
+ sdp_group_attr_val[i].strlen) == 0) {
+ attr_p->attr.stream_data.group_attr = (sdp_group_attr_e)i;
+ break;
+ }
+ }
+
+ if (attr_p->attr.stream_data.group_attr == SDP_GROUP_ATTR_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Group attribute type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+
+ /*
+ * Scan the input line up after group:<attr> to the maximum number
+ * of id available.
+ */
+ attr_p->attr.stream_data.num_group_id =0;
+
+ for (i=0; i<SDP_MAX_MEDIA_STREAMS; i++) {
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.stream_data.group_ids[i] = cpr_strdup(tmp);
+ if (!attr_p->attr.stream_data.group_ids[i]) {
+ break;
+ }
+
+ attr_p->attr.stream_data.num_group_id++;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_group_attr_name (attr_p->attr.stream_data.group_attr));
+ for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
+ SDP_PRINT("%s Parsed group line id : %s\n", sdp_p->debug_str,
+ attr_p->attr.stream_data.group_ids[i]);
+ }
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:%s",
+ sdp_attr[attr_p->type].name,
+ sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr));
+
+ for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
+ if (attr_p->attr.stream_data.group_ids[i]) {
+ flex_string_sprintf(fs, " %s",
+ attr_p->attr.stream_data.group_ids[i]);
+ }
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+/* Parse the source-filter attribute
+ * "a=source-filter:<filter-mode><filter-spec>"
+ * <filter-spec> = <nettype><addrtype><dest-addr><src_addr><src_addr>...
+ */
+sdp_result_e sdp_parse_attr_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.source_filter.mode = SDP_FILTER_MODE_NOT_PRESENT;
+ attr_p->attr.source_filter.nettype = SDP_NT_UNSUPPORTED;
+ attr_p->attr.source_filter.addrtype = SDP_AT_UNSUPPORTED;
+ attr_p->attr.source_filter.dest_addr[0] = '\0';
+ attr_p->attr.source_filter.num_src_addr = 0;
+
+ /* Find the filter mode */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No src filter attribute value specified for "
+ "a=source-filter line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_FILTER_MODE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_src_filter_mode_val[i].name,
+ sdp_src_filter_mode_val[i].strlen) == 0) {
+ attr_p->attr.source_filter.mode = (sdp_src_filter_mode_e)i;
+ break;
+ }
+ }
+ if (attr_p->attr.source_filter.mode == SDP_FILTER_MODE_NOT_PRESENT) {
+ /* No point continuing */
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid src filter mode for a=source-filter "
+ "line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the network type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ attr_p->attr.source_filter.nettype = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (attr_p->attr.source_filter.nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Network type unsupported "
+ "(%s) for a=source-filter", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the address type */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ attr_p->attr.source_filter.addrtype = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if (attr_p->attr.source_filter.addrtype == SDP_AT_UNSUPPORTED) {
+ if (strncmp(tmp, "*", 1) == 0) {
+ attr_p->attr.source_filter.addrtype = SDP_AT_FQDN;
+ } else {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Address type unsupported "
+ "(%s) for a=source-filter", sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ /* Find the destination addr */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.dest_addr,
+ sizeof(attr_p->attr.source_filter.dest_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No filter destination address specified for "
+ "a=source-filter", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the list of source address to apply the filter */
+ for (i = 0; i < SDP_MAX_SRC_ADDR_LIST; i++) {
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.src_list[i],
+ sizeof(attr_p->attr.source_filter.src_list[i]), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ attr_p->attr.source_filter.num_src_addr++;
+ }
+ if (attr_p->attr.source_filter.num_src_addr == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No source list provided "
+ "for a=source-filter", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+
+ flex_string_sprintf(fs, "a=%s:%s %s %s %s",
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_src_filter_mode_name(attr_p->attr.source_filter.mode),
+ sdp_get_network_name(attr_p->attr.source_filter.nettype),
+ sdp_get_address_name(attr_p->attr.source_filter.addrtype),
+ attr_p->attr.source_filter.dest_addr);
+
+ for (i = 0; i < attr_p->attr.source_filter.num_src_addr; i++) {
+ flex_string_append(fs, " ");
+ flex_string_append(fs, attr_p->attr.source_filter.src_list[i]);
+ }
+
+ flex_string_append(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+/* Parse the rtcp-unicast attribute
+ * "a=rtcp-unicast:<reflection|rsi>"
+ */
+sdp_result_e sdp_parse_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ uint32_t i;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ attr_p->attr.u32_val = SDP_RTCP_UNICAST_MODE_NOT_PRESENT;
+
+ memset(tmp, 0, sizeof(tmp));
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No rtcp unicast mode specified for "
+ "a=rtcp-unicast line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i = 0; i < SDP_RTCP_MAX_UNICAST_MODE; i++) {
+ if (cpr_strncasecmp(tmp, sdp_rtcp_unicast_mode_val[i].name,
+ sdp_rtcp_unicast_mode_val[i].strlen) == 0) {
+ attr_p->attr.u32_val = i;
+ break;
+ }
+ }
+ if (attr_p->attr.u32_val == SDP_RTCP_UNICAST_MODE_NOT_PRESENT) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid rtcp unicast mode for "
+ "a=rtcp-unicast line", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ if (attr_p->attr.u32_val >= SDP_RTCP_MAX_UNICAST_MODE) {
+ return SDP_INVALID_PARAMETER;
+ }
+
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_get_attr_name(attr_p->type),
+ sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val));
+
+ return SDP_SUCCESS;
+}
+
+
+/*
+ * store_sdescriptions_mki_or_lifetime
+ *
+ * Verifies the syntax of the MKI or lifetime parameter and stores
+ * it in the sdescriptions attribute struct.
+ *
+ * Inputs:
+ * buf - pointer to MKI or lifetime string assumes string is null
+ * terminated.
+ * attr_p - pointer to attribute struct
+ *
+ * Outputs:
+ * Return TRUE all is good otherwise FALSE for error.
+ */
+
+tinybool
+store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p)
+{
+
+ tinybool result;
+ uint16_t mkiLen;
+ char mkiValue[SDP_SRTP_MAX_MKI_SIZE_BYTES];
+
+ /* MKI has a colon */
+ if (strstr(buf, ":")) {
+ result = verify_sdescriptions_mki(buf, mkiValue, &mkiLen);
+ if (result) {
+ attr_p->attr.srtp_context.mki_size_bytes = mkiLen;
+ sstrncpy((char*)attr_p->attr.srtp_context.mki, mkiValue,
+ SDP_SRTP_MAX_MKI_SIZE_BYTES);
+ }
+
+ } else {
+ result = verify_sdescriptions_lifetime(buf);
+ if (result) {
+ sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
+ SDP_SRTP_MAX_LIFETIME_BYTES);
+ }
+ }
+
+ return result;
+
+}
+
+/*
+ * sdp_parse_sdescriptions_key_param
+ *
+ * This routine parses the srtp key-params pointed to by str.
+ *
+ * key-params = <key-method> ":" <key-info>
+ * key-method = "inline" / key-method-ext [note V9 only supports 'inline']
+ * key-info = srtp-key-info
+ * srtp-key-info = key-salt ["|" lifetime] ["|" mki]
+ * key-salt = 1*(base64) ; binary key and salt values
+ * ; concatenated together, and then
+ * ; base64 encoded [section 6.8 of
+ * ; RFC2046]
+ *
+ * lifetime = ["2^"] 1*(DIGIT)
+ * mki = mki-value ":" mki-length
+ * mki-value = 1*DIGIT
+ * mki-length = 1*3DIGIT ; range 1..128.
+ *
+ * Inputs: str - pointer to beginning of key-params and assumes
+ * null terminated string.
+ */
+
+
+tinybool
+sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p,
+ sdp_t *sdp_p)
+{
+ char buf[SDP_MAX_STRING_LEN],
+ base64decodeData[SDP_MAX_STRING_LEN];
+ const char *ptr;
+ sdp_result_e result = SDP_SUCCESS;
+ tinybool keyFound = FALSE;
+ int len,
+ keySize,
+ saltSize;
+ base64_result_t status;
+
+ ptr = str;
+ if (cpr_strncasecmp(ptr, "inline:", 7) != 0) {
+ sdp_parse_error(sdp_p,
+ "%s Could not find keyword inline", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ /* advance pass the inline key word */
+ ptr = ptr + 7;
+ ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
+ while (result == SDP_SUCCESS) {
+ /* the fist time this loop executes, the key is gotten */
+ if (keyFound == FALSE) {
+ keyFound = TRUE;
+ len = SDP_MAX_STRING_LEN;
+ /* The key is base64 encoded composed of the master key concatenated with the
+ * master salt.
+ */
+ status = base64_decode((unsigned char *)buf, strlen(buf),
+ (unsigned char *)base64decodeData, &len);
+
+ if (status != BASE64_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s key-salt error decoding buffer: %s",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ return FALSE;
+ }
+
+ keySize = attr_p->attr.srtp_context.master_key_size_bytes;
+ saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ if (len != keySize + saltSize) {
+ sdp_parse_error(sdp_p,
+ "%s key-salt size doesn't match: (%d, %d, %d)",
+ sdp_p->debug_str, len, keySize, saltSize);
+ return(FALSE);
+ }
+
+ memcpy(attr_p->attr.srtp_context.master_key,
+ base64decodeData,
+ keySize);
+
+ memcpy(attr_p->attr.srtp_context.master_salt,
+ base64decodeData + keySize,
+ saltSize);
+
+ /* Used only for MGCP */
+ SDP_SRTP_CONTEXT_SET_MASTER_KEY
+ (attr_p->attr.srtp_context.selection_flags);
+ SDP_SRTP_CONTEXT_SET_MASTER_SALT
+ (attr_p->attr.srtp_context.selection_flags);
+
+ } else if (store_sdescriptions_mki_or_lifetime(buf, attr_p) == FALSE) {
+ return FALSE;
+ }
+
+ /* if we haven't reached the end of line, get the next token */
+ ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
+ }
+
+ /* if we didn't find the key, error out */
+ if (keyFound == FALSE) {
+ sdp_parse_error(sdp_p,
+ "%s Could not find sdescriptions key", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/*
+ * sdp_build_attr_sdescriptions
+ *
+ * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS.
+ *
+ * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params
+ *
+ * Where key-params = inline: <key|salt> ["|"lifetime] ["|" MKI:length]
+ * The key and salt is base64 encoded and lifetime and MKI/length are optional.
+ */
+
+sdp_result_e
+sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+
+ unsigned char base64_encoded_data[MAX_BASE64_STRING_LEN];
+ unsigned char base64_encoded_input[MAX_BASE64_STRING_LEN];
+ int keySize,
+ saltSize,
+ outputLen;
+ base64_result_t status;
+
+ keySize = attr_p->attr.srtp_context.master_key_size_bytes;
+ saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
+
+ /* concatenate the master key + salt then base64 encode it */
+ memcpy(base64_encoded_input,
+ attr_p->attr.srtp_context.master_key,
+ keySize);
+
+ memcpy(base64_encoded_input + keySize,
+ attr_p->attr.srtp_context.master_salt,
+ saltSize);
+
+ outputLen = MAX_BASE64_STRING_LEN;
+ status = base64_encode(base64_encoded_input, keySize + saltSize,
+ base64_encoded_data, &outputLen);
+
+ if (status != BASE64_SUCCESS) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
+ sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
+ }
+ return (SDP_INVALID_PARAMETER);
+
+ }
+
+ base64_encoded_data[outputLen] = 0;
+
+ /* lifetime and MKI parameters are optional. Only inlcude them if
+ * they were set.
+ */
+
+
+ if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0 &&
+ attr_p->attr.srtp_context.mki[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s|%s:%d\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.master_key_lifetime,
+ attr_p->attr.srtp_context.mki,
+ attr_p->attr.srtp_context.mki_size_bytes);
+
+ return SDP_SUCCESS;
+ }
+
+ /* if we get here, either lifetime is populated and mki and is not or mki is populated
+ * and lifetime is not or neither is populated
+ */
+
+ if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.master_key_lifetime);
+
+ } else if (attr_p->attr.srtp_context.mki[0] != 0) {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s:%d\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data,
+ attr_p->attr.srtp_context.mki,
+ attr_p->attr.srtp_context.mki_size_bytes);
+
+ } else {
+ flex_string_sprintf(fs, "a=%s:%d %s inline:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ attr_p->attr.srtp_context.tag,
+ sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
+ base64_encoded_data);
+
+ }
+
+ return SDP_SUCCESS;
+
+}
+
+
+/*
+ * sdp_parse_attr_srtp
+ *
+ * Parses Session Description for Protocol Security Descriptions
+ * version 2 or version 9. Grammar is of the form:
+ *
+ * a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
+ *
+ * Note session-params is not supported and will not be parsed.
+ * Version 2 does not contain a tag.
+ *
+ * Inputs:
+ * sdp_p - pointer to sdp handle
+ * attr_p - pointer to attribute structure
+ * ptr - pointer to string to be parsed
+ * vtype - version type
+ */
+
+sdp_result_e
+sdp_parse_attr_srtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr, sdp_attr_e vtype)
+{
+
+ char tmp[SDP_MAX_STRING_LEN];
+ sdp_result_e result = SDP_FAILURE;
+ int k = 0;
+
+ /* initialize only the optional parameters */
+ attr_p->attr.srtp_context.master_key_lifetime[0] = 0;
+ attr_p->attr.srtp_context.mki[0] = 0;
+
+ /* used only for MGCP */
+ SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
+ (attr_p->attr.srtp_context.selection_flags);
+
+ /* get the tag only if we are version 9 */
+ if (vtype == SDP_ATTR_SDESCRIPTIONS) {
+ attr_p->attr.srtp_context.tag =
+ sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Could not find sdescriptions tag",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+
+ }
+ }
+
+ /* get the crypto suite */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Could not find sdescriptions crypto suite", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!sdp_parse_context_crypto_suite(tmp, attr_p, sdp_p)) {
+ sdp_parse_error(sdp_p,
+ "%s Unsupported crypto suite", sdp_p->debug_str);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Could not find sdescriptions key params", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!sdp_parse_sdescriptions_key_param(tmp, attr_p, sdp_p)) {
+ sdp_parse_error(sdp_p,
+ "%s Failed to parse key-params", sdp_p->debug_str);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* if there are session parameters, scan the session parameters
+ * into tmp until we reach end of line. Currently the sdp parser
+ * does not parse session parameters but if they are present,
+ * we store them for the application.
+ */
+ /*sa_ignore NO_NULL_CHK
+ *{ptr is valid since the pointer was checked earlier and the
+ * function would have exited if NULL.}
+ */
+ while (*ptr && *ptr != '\n' && *ptr != '\r' && k < SDP_MAX_STRING_LEN) {
+ tmp[k++] = *ptr++;
+ }
+
+ if ((k) && (k < SDP_MAX_STRING_LEN)) {
+ tmp[k] = 0;
+ attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp);
+ }
+
+ return SDP_SUCCESS;
+
+}
+
+/* Parses crypto attribute based on the sdescriptions version
+ * 9 grammar.
+ *
+ */
+
+sdp_result_e
+sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+
+ return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
+ SDP_ATTR_SDESCRIPTIONS);
+
+}
+
+/* Parses X-crypto attribute based on the sdescriptions version
+ * 2 grammar.
+ *
+ */
+
+sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+
+ return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
+ SDP_ATTR_SRTP_CONTEXT);
+}
+
+
+sdp_result_e sdp_build_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs) {
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.ice_attr);
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) {
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "\r\n", &result);
+ if (result != SDP_SUCCESS){
+ sdp_parse_error(sdp_p,
+ "%s Warning: problem parsing ice attribute ", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ snprintf(attr_p->attr.ice_attr, sizeof(attr_p->attr.ice_attr), "%s", tmp);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp);
+ }
+ return (SDP_SUCCESS);
+}
+
+
+sdp_result_e sdp_build_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs) {
+ flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr) {
+ /* No parameters to parse. */
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type));
+ }
+
+ return (SDP_SUCCESS);
+}
+
+static sdp_result_e sdp_parse_attr_line(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr, char *buf, size_t buf_len) {
+ sdp_result_e result;
+
+ (void)sdp_getnextstrtok(ptr, buf, buf_len, "\r\n", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No string token found for %s attribute",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ buf);
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ return sdp_parse_attr_line(sdp_p, attr_p, ptr,
+ attr_p->attr.string_val,
+ sizeof(attr_p->attr.string_val));
+}
+
+sdp_result_e sdp_parse_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ char buffer[SDP_MAX_LONG_STRING_LEN];
+
+ result = sdp_parse_attr_line(sdp_p, attr_p, ptr,
+ buffer, sizeof(buffer));
+ if (result == SDP_SUCCESS) {
+ attr_p->attr.stringp = cpr_strdup(buffer);
+ }
+ return result;
+}
+
+sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
+ attr_p->attr.stringp);
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
+
+ /* Payload Type */
+ if (attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) {
+ flex_string_sprintf(fs, "* ");
+ } else {
+ flex_string_sprintf(fs, "%d ",attr_p->attr.rtcp_fb.payload_num);
+ }
+
+ /* Feedback Type */
+ if (attr_p->attr.rtcp_fb.feedback_type < SDP_RTCP_FB_UNKNOWN) {
+ flex_string_sprintf(fs, "%s",
+ sdp_rtcp_fb_type_val[attr_p->attr.rtcp_fb.feedback_type].name);
+ }
+
+ /* Feedback Type Parameters */
+ switch (attr_p->attr.rtcp_fb.feedback_type) {
+ case SDP_RTCP_FB_ACK:
+ if (attr_p->attr.rtcp_fb.param.ack < SDP_MAX_RTCP_FB_ACK) {
+ flex_string_sprintf(fs, " %s",
+ sdp_rtcp_fb_ack_type_val[attr_p->attr.rtcp_fb.param.ack]
+ .name);
+ }
+ break;
+ case SDP_RTCP_FB_CCM: /* RFC 5104 */
+ if (attr_p->attr.rtcp_fb.param.ccm < SDP_MAX_RTCP_FB_CCM) {
+ flex_string_sprintf(fs, " %s",
+ sdp_rtcp_fb_ccm_type_val[attr_p->attr.rtcp_fb.param.ccm]
+ .name);
+ }
+ break;
+ case SDP_RTCP_FB_NACK:
+ if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_BASIC
+ && attr_p->attr.rtcp_fb.param.nack < SDP_MAX_RTCP_FB_NACK) {
+ flex_string_sprintf(fs, " %s",
+ sdp_rtcp_fb_nack_type_val[attr_p->attr.rtcp_fb.param.nack]
+ .name);
+ }
+ break;
+ case SDP_RTCP_FB_TRR_INT:
+ flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int);
+ break;
+ case SDP_RTCP_FB_REMB:
+ /* No additional params after REMB */
+ break;
+
+ case SDP_RTCP_FB_UNKNOWN:
+ /* Contents are in the "extra" field */
+ break;
+
+ default:
+ CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
+ sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
+ return SDP_FAILURE;
+ }
+
+ /* Tack on any information that cannot otherwise be represented by
+ * the sdp_fmtp_fb_t structure. */
+ if (attr_p->attr.rtcp_fb.extra[0]) {
+ flex_string_sprintf(fs, " %s", attr_p->attr.rtcp_fb.extra);
+ }
+
+ /* Line ending */
+ flex_string_sprintf(fs, "\r\n");
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_rtcp_fb (sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result = SDP_SUCCESS;
+ sdp_fmtp_fb_t *rtcp_fb_p = &(attr_p->attr.rtcp_fb);
+ int i;
+
+ /* Set up attribute fields */
+ rtcp_fb_p->payload_num = 0;
+ rtcp_fb_p->feedback_type = SDP_RTCP_FB_UNKNOWN;
+ rtcp_fb_p->extra[0] = '\0';
+
+ /* Skip WS (just in case) */
+ while (*ptr == ' ' || *ptr == '\t') {
+ ptr++;
+ }
+
+ /* Look for the special "*" payload type */
+ if (*ptr == '*') {
+ rtcp_fb_p->payload_num = SDP_ALL_PAYLOADS;
+ ptr++;
+ } else {
+ /* If the pt is not '*', parse it out as an integer */
+ rtcp_fb_p->payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse payload type for rtcp-fb attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ /* Read feedback type */
+ i = find_token_enum("rtcp-fb attribute", sdp_p, &ptr, sdp_rtcp_fb_type_val,
+ SDP_MAX_RTCP_FB, SDP_RTCP_FB_UNKNOWN);
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse feedback type for rtcp-fb attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_fb_p->feedback_type = (sdp_rtcp_fb_type_e) i;
+
+ switch(rtcp_fb_p->feedback_type) {
+ case SDP_RTCP_FB_ACK:
+ i = find_token_enum("rtcp-fb ack type", sdp_p, &ptr,
+ sdp_rtcp_fb_ack_type_val,
+ SDP_MAX_RTCP_FB_ACK, SDP_RTCP_FB_ACK_UNKNOWN);
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse ack type for rtcp-fb attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_fb_p->param.ack = (sdp_rtcp_fb_ack_type_e) i;
+ break;
+
+ case SDP_RTCP_FB_CCM:
+ i = find_token_enum("rtcp-fb ccm type", sdp_p, &ptr,
+ sdp_rtcp_fb_ccm_type_val,
+ SDP_MAX_RTCP_FB_CCM, SDP_RTCP_FB_CCM_UNKNOWN);
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse ccm type for rtcp-fb attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_fb_p->param.ccm = (sdp_rtcp_fb_ccm_type_e) i;
+
+ /* TODO -- We don't currently parse tmmbr parameters or vbcm
+ submessage types. If we decide to support these modes of
+ operation, we probably want to add parsing code for them.
+ For the time being, they'll just end up parsed into "extra"
+ Bug 1097169.
+ */
+ break;
+
+ case SDP_RTCP_FB_NACK:
+ /* Skip any remaining WS -- see
+ http://code.google.com/p/webrtc/issues/detail?id=1922 */
+ while (*ptr == ' ' || *ptr == '\t') {
+ ptr++;
+ }
+ /* Check for empty string */
+ if (*ptr == '\r') {
+ rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC;
+ break;
+ }
+ i = find_token_enum("rtcp-fb nack type", sdp_p, &ptr,
+ sdp_rtcp_fb_nack_type_val,
+ SDP_MAX_RTCP_FB_NACK, SDP_RTCP_FB_NACK_UNKNOWN);
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse nack type for rtcp-fb attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ rtcp_fb_p->param.nack = (sdp_rtcp_fb_nack_type_e) i;
+ break;
+
+ case SDP_RTCP_FB_TRR_INT:
+ rtcp_fb_p->param.trr_int = sdp_getnextnumtok(ptr, &ptr,
+ " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse trr-int value for rtcp-fb "
+ "attribute", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ break;
+
+ case SDP_RTCP_FB_REMB:
+ /* No additional tokens to parse after goog-remb */
+ break;
+
+ case SDP_RTCP_FB_UNKNOWN:
+ /* Handled by "extra", below */
+ break;
+
+ default:
+ /* This is an internal error, not a parsing error */
+ CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
+ sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
+ return SDP_FAILURE;
+ }
+
+ /* Skip any remaining WS */
+ while (*ptr == ' ' || *ptr == '\t') {
+ ptr++;
+ }
+
+ /* Just store the rest of the line in "extra" -- this will return
+ a failure result if there is no more text, but that's fine. */
+ ptr = sdp_getnextstrtok(ptr, rtcp_fb_p->extra,
+ sizeof(rtcp_fb_p->extra), "\r\n", &result);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ switch (attr_p->attr.setup) {
+ case SDP_SETUP_ACTIVE:
+ case SDP_SETUP_PASSIVE:
+ case SDP_SETUP_ACTPASS:
+ case SDP_SETUP_HOLDCONN:
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_setup_type_val[attr_p->attr.setup].name);
+ break;
+ default:
+ CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
+ sdp_p->debug_str, attr_p->attr.setup);
+ return SDP_FAILURE;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i = find_token_enum("setup attribute", sdp_p, &ptr,
+ sdp_setup_type_val,
+ SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
+
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse setup attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ attr_p->attr.setup = (sdp_setup_type_e) i;
+
+ switch (attr_p->attr.setup) {
+ case SDP_SETUP_ACTIVE:
+ case SDP_SETUP_PASSIVE:
+ case SDP_SETUP_ACTPASS:
+ case SDP_SETUP_HOLDCONN:
+ /* All these values are OK */
+ break;
+ case SDP_SETUP_UNKNOWN:
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unknown setup attribute",
+ sdp_p->debug_str);
+ return SDP_INVALID_PARAMETER;
+ default:
+ /* This is an internal error, not a parsing error */
+ CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
+ sdp_p->debug_str, attr_p->attr.setup);
+ return SDP_FAILURE;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ switch (attr_p->attr.connection) {
+ case SDP_CONNECTION_NEW:
+ case SDP_CONNECTION_EXISTING:
+ flex_string_sprintf(fs, "a=%s:%s\r\n",
+ sdp_attr[attr_p->type].name,
+ sdp_connection_type_val[attr_p->attr.connection].name);
+ break;
+ default:
+ CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
+ sdp_p->debug_str, attr_p->attr.connection);
+ return SDP_FAILURE;
+ }
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ int i = find_token_enum("connection attribute", sdp_p, &ptr,
+ sdp_connection_type_val,
+ SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
+
+ if (i < 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: could not parse connection attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ attr_p->attr.connection = (sdp_connection_type_e) i;
+
+ switch (attr_p->attr.connection) {
+ case SDP_CONNECTION_NEW:
+ case SDP_CONNECTION_EXISTING:
+ /* All these values are OK */
+ break;
+ case SDP_CONNECTION_UNKNOWN:
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unknown connection attribute",
+ sdp_p->debug_str);
+ return SDP_INVALID_PARAMETER;
+ default:
+ /* This is an internal error, not a parsing error */
+ CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
+ sdp_p->debug_str, attr_p->attr.connection);
+ return SDP_FAILURE;
+ }
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
+ attr_p->attr.extmap.id,
+ attr_p->attr.extmap.uri);
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.extmap.id = 0;
+ attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
+ attr_p->attr.extmap.media_direction_specified = FALSE;
+ attr_p->attr.extmap.uri[0] = '\0';
+ attr_p->attr.extmap.extension_attributes[0] = '\0';
+
+ /* Find the payload type number. */
+ attr_p->attr.extmap.id =
+ (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid extmap id specified for %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (*ptr == '/') {
+ char direction[SDP_MAX_STRING_LEN+1];
+ ++ptr; /* Skip over '/' */
+ ptr = sdp_getnextstrtok(ptr, direction,
+ sizeof(direction), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid direction specified in %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (!cpr_strcasecmp(direction, "sendrecv")) {
+ attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
+ } else if (!cpr_strcasecmp(direction, "sendonly")) {
+ attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDONLY;
+ } else if (!cpr_strcasecmp(direction, "recvonly")) {
+ attr_p->attr.extmap.media_direction = SDP_DIRECTION_RECVONLY;
+ } else if (!cpr_strcasecmp(direction, "inactive")) {
+ attr_p->attr.extmap.media_direction = SDP_DIRECTION_INACTIVE;
+ } else {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid direction specified in %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.extmap.media_direction_specified = TRUE;
+ }
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri,
+ sizeof(attr_p->attr.extmap.uri), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No uri specified in %s attribute.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ while (*ptr == ' ' || *ptr == '\t') {
+ ++ptr;
+ }
+
+ /* Grab everything that follows, even if it contains whitespace */
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes,
+ sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
+ "uri %s, extension %s", sdp_p->debug_str,
+ sdp_get_attr_name(attr_p->type),
+ attr_p->attr.extmap.id,
+ SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
+ attr_p->attr.extmap.uri,
+ attr_p->attr.extmap.extension_attributes);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.identifier,
+ sizeof(attr_p->attr.msid.identifier), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p, "%s Warning: Bad msid identity value",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.appdata,
+ sizeof(attr_p->attr.msid.appdata), " \t", &result);
+ if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
+ sdp_parse_error(sdp_p, "%s Warning: Bad msid appdata value",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ if (result == SDP_EMPTY_TOKEN) {
+ attr_p->attr.msid.appdata[0] = '\0';
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=msid, %s %s", sdp_p->debug_str,
+ attr_p->attr.msid.identifier, attr_p->attr.msid.appdata);
+ }
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=msid:%s%s%s\r\n",
+ attr_p->attr.msid.identifier,
+ attr_p->attr.msid.appdata[0] ? " " : "",
+ attr_p->attr.msid.appdata);
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+ int i;
+
+ ptr = sdp_getnextstrtok(ptr,
+ attr_p->attr.msid_semantic.semantic,
+ sizeof(attr_p->attr.msid_semantic.semantic),
+ " \t",
+ &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; "
+ "missing semantic",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
+ /* msid-id can be up to 64 characters long, plus null terminator */
+ char temp[65];
+ ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+
+ attr_p->attr.msid_semantic.msids[i] = cpr_strdup(temp);
+ }
+
+ if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
+ sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed a=msid-semantic, %s", sdp_p->debug_str,
+ attr_p->attr.msid_semantic.semantic);
+ for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
+ if (!attr_p->attr.msid_semantic.msids[i]) {
+ break;
+ }
+
+ SDP_PRINT("%s ... msid %s", sdp_p->debug_str,
+ attr_p->attr.msid_semantic.msids[i]);
+ }
+ }
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ int i;
+ flex_string_sprintf(fs, "a=msid-semantic:%s",
+ attr_p->attr.msid_semantic.semantic);
+ for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
+ if (!attr_p->attr.msid_semantic.msids[i]) {
+ break;
+ }
+
+ flex_string_sprintf(fs, " %s",
+ attr_p->attr.msid_semantic.msids[i]);
+ }
+ flex_string_sprintf(fs, "\r\n");
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr)
+{
+ sdp_result_e result;
+
+ attr_p->attr.ssrc.ssrc =
+ (uint32_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p, "%s Warning: Bad ssrc attribute, cannot parse ssrc",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ /* Skip any remaining WS */
+ while (*ptr == ' ' || *ptr == '\t') {
+ ptr++;
+ }
+
+ /* Just store the rest of the line in "attribute" -- this will return
+ a failure result if there is no more text, but that's fine. */
+ ptr = sdp_getnextstrtok(ptr,
+ attr_p->attr.ssrc.attribute,
+ sizeof(attr_p->attr.ssrc.attribute),
+ "\r\n",
+ &result);
+
+ return SDP_SUCCESS;
+}
+
+
+sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs)
+{
+ flex_string_sprintf(fs, "a=ssrc:%s%s%s\r\n",
+ attr_p->attr.ssrc.ssrc,
+ attr_p->attr.ssrc.attribute[0] ? " " : "",
+ attr_p->attr.ssrc.attribute);
+ return SDP_SUCCESS;
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c
new file mode 100644
index 000000000..0562e537e
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_attr_access.c
@@ -0,0 +1,6372 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+static const char* logTag = "sdp_attr_access";
+
+/* Attribute access routines are all defined by the following parameters.
+ *
+ * sdp_p The SDP handle returned by sdp_init_description.
+ * level The level the attribute is defined. Can be either
+ * SDP_SESSION_LEVEL or 0-n specifying a media line level.
+ * inst_num The instance number of the attribute. Multiple instances
+ * of a particular attribute may exist at each level and so
+ * the inst_num determines the particular attribute at that
+ * level that should be accessed. Note that this is the
+ * instance number of the specified type of attribute, not the
+ * overall attribute number at the level. Also note that the
+ * instance number is 1-based. For example:
+ * v=0
+ * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ * s=SDP Seminar
+ * c=IN IP4 10.1.0.2
+ * t=0 0
+ * m=audio 1234 RTP/AVP 0 101 102
+ * a=foo 1
+ * a=foo 2
+ * a=bar 1 # This is instance 1 of attribute bar.
+ * a=foo 3 # This is instance 3 of attribute foo.
+ * cap_num Almost all of the attributes may be defined as X-cpar
+ * parameters (with the exception of X-sqn, X-cap, and X-cpar).
+ * If the cap_num is set to zero, then the attribute is not
+ * an X-cpar parameter attribute. If the cap_num is any other
+ * value, it specifies the capability number that the X-cpar
+ * attribute is specified for.
+ */
+
+/* Attribute handling:
+ *
+ * There are two basic types of attributes handled by the SDP library,
+ * those defined by a= token lines, and those embedded with a=X-cpar lines.
+ * The handling for each of these is described here.
+ *
+ * Simple (non X-cpar attributes):
+ *
+ * Attributes not embedded in a=X-cpar lines are referenced by level and
+ * instance number. For these attributes the capability number is always
+ * set to zero.
+ *
+ * An application will typically process these attributes in one of two ways.
+ * With the first method, the application can determine the total number
+ * of attributes defined at a given level and process them one at a time.
+ * For each attribute, the application will query the library to find out
+ * what type of attribute it is and which instance within that type. The
+ * application can then process this particular attribute referencing it
+ * by level and instance number.
+ *
+ * A second method of processing attributes is for applications to determine
+ * each type of attribute they are interested in, query the SDP library to
+ * find out how many of that type of attribute exist at a given level, and
+ * process each one at a time.
+ *
+ * X-cpar attribute processing:
+ *
+ * X-cpar attributes can contain embedded attributes. They are associated
+ * with X-cap attribute lines. An example of X-cap and X-cpar attributes
+ * found in an SDP is as follows:
+ *
+ * v=0
+ * o=- 25678 753849 IN IP4 128.96.41.1
+ * s=-
+ * t=0 0
+ * c=IN IP4 10.1.0.2
+ * m=audio 3456 RTP/AVP 18 96
+ * a=rtpmap:96 telephone-event/8000
+ * a=fmtp:96 0-15,32-35
+ * a=X-sqn: 0
+ * a=X-cap: 1 audio RTP/AVP 0 18 96 97
+ * a=X-cpar: a=fmtp:96 0-16,32-35
+ * a=X-cpar: a=rtpmap:97 X-NSE/8000
+ * a=X-cpar: a=fmtp:97 195-197
+ * a=X-cap: 5 image udptl t38
+ * a=X-cap: 6 application udp X-tmr
+ * a=X-cap: 7 audio RTP/AVP 100 101
+ * a=X-cpar: a=rtpmap:100 g.711/8000
+ * a=X-cpar: a=rtpmap:101 g.729/8000
+ *
+ * X-cap attributes can be defined at the SESSION_LEVEL or any media level.
+ * An X-cap attr is defined by the level and instance number just like
+ * other attributes. In the example above, X-cap attrs are defined at
+ * media level 1 and there are four instances at that level.
+ *
+ * The X-cpar attributes can also be referenced by level and instance number.
+ * However, the embedded attribute within an X-cpar attribute must be
+ * referenced by level, instance number, and capability number. This is
+ * because the X-cpar attribute is associated with a particular X-cap/
+ * capability.
+ * For all attributes that are not embedded within an X-cpar attribute, the
+ * cap_num should be referenced as zero. But for X-cpar attributes, the
+ * cap_num is specified to be one of the capability numbers of the previous
+ * X-cap line. The number of capabilities specified in an X-cap line is
+ * equal to the number of payloads. Thus, in this example, the first X-cap
+ * attr instance specifies capabilities 1-4, the second specifies capability
+ * 5, the third capability 6, and the fourth capabilities 7-8.
+ *
+ * X-cpar attributes can be processed with methods similar to the two
+ * previously mentioned. For each X-cap attribute, the application can
+ * use one of two methods to process the X-cpar attributes. First, it
+ * can query the total number of X-cpar attributes associated with a
+ * given X-cap attribute. The X-cap attribute is here defined by a level
+ * and a capability number. In the example above, the total number of
+ * attributes defined is as follows:
+ * level 1, cap_num 1 - total attrs: 3
+ * level 1, cap_num 5 - total attrs: 0
+ * level 1, cap_num 6 - total attrs: 0
+ * level 1, cap_num 7 - total attrs: 2
+ *
+ * Note that if the application queried the number of attributes for
+ * cap_num 2, 3, or 4, it would also return 3 attrs, and for cap_num
+ * 8 the library would return 2.
+ *
+ * Once the application determines the total number of attributes for
+ * that capability, it can again query the embedded attribute type and
+ * instance. For example, sdp_get_attr_type would return the following:
+ * level 1, cap_num 1, attr 1 -> attr type fmtp, instance 1
+ * level 1, cap_num 1, attr 2 -> attr type rtpmap, instance 1
+ * level 1, cap_num 1, attr 3 -> attr type fmtp, instance 2
+ * level 1, cap_num 7, attr 1 -> attr type rtpmap, instance 1
+ * level 1, cap_num 7, attr 2 -> attr type rtpmap, instance 2
+ *
+ * The individual embedded attributes can then be accessed by level,
+ * cap_num, and instance number.
+ *
+ * With the second method for handling X-cpar attributes, the application
+ * determines the types of attributes it is interested in. It can then
+ * query the SDP library to determine the number of attributes of that
+ * type found for that level and cap_num, and then process each one at
+ * a time. e.g., calling sdp_attr_num_instances would give:
+ * level 1, cap_num 1, attr_type fmtp -> two instances
+ * level 1, cap_num 1, attr_type rtpmap -> one instance
+ * level 1, cap_num 7, attr_type fmtp -> zero instances
+ * level 1, cap_num 7, attr_type rtpmap -> two instances
+ */
+
+
+/* Function: sdp_add_new_attr
+ * Description: Add a new attribute of the specified type at the given
+ * level and capability level or base attribute if cap_num
+ * is zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to add.
+ * inst_num Pointer to a uint16_t in which to return the instance
+ * number of the newly added attribute.
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_NO_RESOURCE No memory avail for new attribute.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_add_new_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t *inst_num)
+{
+ uint16_t i;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *attr_p;
+ sdp_attr_t *new_attr_p;
+ sdp_attr_t *prev_attr_p=NULL;
+ sdp_fmtp_t *fmtp_p;
+ sdp_comediadir_t *comediadir_p;
+
+ *inst_num = 0;
+
+ if ((cap_num != 0) &&
+ ((attr_type == SDP_ATTR_X_CAP) || (attr_type == SDP_ATTR_X_CPAR) ||
+ (attr_type == SDP_ATTR_X_SQN) || (attr_type == SDP_ATTR_CDSC) ||
+ (attr_type == SDP_ATTR_CPAR) || (attr_type == SDP_ATTR_SQN))) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid attribute type for X-cpar/cdsc "
+ "parameter.", sdp_p->debug_str);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Some attributes are valid only under media level */
+ if (level == SDP_SESSION_LEVEL) {
+ switch (attr_type) {
+ case SDP_ATTR_RTCP:
+ case SDP_ATTR_LABEL:
+ return (SDP_INVALID_MEDIA_LEVEL);
+
+ default:
+ break;
+ }
+ }
+
+ new_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
+ if (new_attr_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ new_attr_p->type = attr_type;
+ new_attr_p->next_p = NULL;
+
+ /* Initialize the new attribute structure */
+ if ((new_attr_p->type == SDP_ATTR_X_CAP) ||
+ (new_attr_p->type == SDP_ATTR_CDSC)) {
+ new_attr_p->attr.cap_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t));
+ if (new_attr_p->attr.cap_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+ } else if (new_attr_p->type == SDP_ATTR_FMTP) {
+ fmtp_p = &(new_attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
+ // set to invalid value
+ fmtp_p->packetization_mode = SDP_INVALID_PACKETIZATION_MODE_VALUE;
+ fmtp_p->level_asymmetry_allowed = SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE;
+ fmtp_p->annexb_required = FALSE;
+ fmtp_p->annexa_required = FALSE;
+ fmtp_p->maxval = 0;
+ fmtp_p->bitrate = 0;
+ fmtp_p->cif = 0;
+ fmtp_p->qcif = 0;
+ fmtp_p->profile = SDP_INVALID_VALUE;
+ fmtp_p->level = SDP_INVALID_VALUE;
+ fmtp_p->parameter_add = SDP_FMTP_UNUSED;
+ fmtp_p->usedtx = SDP_FMTP_UNUSED;
+ fmtp_p->stereo = SDP_FMTP_UNUSED;
+ fmtp_p->useinbandfec = SDP_FMTP_UNUSED;
+ fmtp_p->cbr = SDP_FMTP_UNUSED;
+ for (i=0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ fmtp_p->bmap[i] = 0;
+ }
+ } else if ((new_attr_p->type == SDP_ATTR_RTPMAP) ||
+ (new_attr_p->type == SDP_ATTR_SPRTMAP)) {
+ new_attr_p->attr.transport_map.num_chan = 1;
+ } else if (new_attr_p->type == SDP_ATTR_DIRECTION) {
+ comediadir_p = &(new_attr_p->attr.comediadir);
+ comediadir_p->role = SDP_MEDIADIR_ROLE_PASSIVE;
+ comediadir_p->conn_info_present = FALSE;
+ } else if (new_attr_p->type == SDP_ATTR_MPTIME) {
+ sdp_mptime_t *mptime = &(new_attr_p->attr.mptime);
+ mptime->num_intervals = 0;
+ }
+
+ if (cap_num == 0) {
+ /* Add a new attribute. */
+ if (level == SDP_SESSION_LEVEL) {
+ if (sdp_p->sess_attrs_p == NULL) {
+ sdp_p->sess_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = sdp_p->sess_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (mca_p->media_attrs_p == NULL) {
+ mca_p->media_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = mca_p->media_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+ } else {
+ /* Add a new capability attribute - find the capability attr. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ sdp_free_attr(new_attr_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ cap_p = attr_p->attr.cap_p;
+ if (cap_p->media_attrs_p == NULL) {
+ cap_p->media_attrs_p = new_attr_p;
+ } else {
+ for (attr_p = cap_p->media_attrs_p;
+ attr_p != NULL;
+ prev_attr_p = attr_p, attr_p = attr_p->next_p) {
+ /* Count the num instances of this type. */
+ if (attr_p->type == attr_type) {
+ (*inst_num)++;
+ }
+ }
+ prev_attr_p->next_p = new_attr_p;
+ }
+ }
+
+ /* Increment the instance num for the attr just added. */
+ (*inst_num)++;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_num_instances
+ * Description: Get the number of attributes of the specified type at
+ * the given level and capability level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to add.
+ * num_attr_inst Pointer to a uint16_t in which to return the
+ * number of attributes.
+ * Returns: SDP_SUCCESS Attribute was added successfully.
+ * SDP_INVALID_PARAMETER Specified media line is not defined.
+ */
+sdp_result_e sdp_attr_num_instances (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t *num_attr_inst)
+{
+ sdp_attr_t *attr_p;
+ sdp_result_e rc;
+ static char fname[] = "attr_num_instances";
+
+ *num_attr_inst = 0;
+
+ rc = sdp_find_attr_list(sdp_p, level, cap_num, &attr_p, fname);
+ if (rc == SDP_SUCCESS) {
+ /* Found the attr list. Count the number of attrs of the given
+ * type at this level. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ (*num_attr_inst)++;
+ }
+ }
+
+ }
+
+ return (rc);
+}
+
+/* Forward declaration for use in sdp_free_attr */
+static boolean sdp_attr_is_long_string(sdp_attr_e attr_type);
+
+
+/* Internal routine to free the memory associated with an attribute.
+ * Certain attributes allocate additional memory. Free this and then
+ * free the attribute itself.
+ * Note that this routine may be called at any point (i.e., may be
+ * called due to a failure case) and so the additional memory
+ * associated with an attribute may or may not have been already
+ * allocated. This routine should check this carefully.
+ */
+void sdp_free_attr (sdp_attr_t *attr_p)
+{
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cpar_p;
+ sdp_attr_t *next_cpar_p;
+ int i;
+
+ /* If this is an X-cap/cdsc attr, free the cap_p structure and
+ * all X-cpar/cpar attributes. */
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ if (cap_p != NULL) {
+ for (cpar_p = cap_p->media_attrs_p; cpar_p != NULL;) {
+ next_cpar_p = cpar_p->next_p;
+ sdp_free_attr(cpar_p);
+ cpar_p = next_cpar_p;
+ }
+ SDP_FREE(cap_p);
+ }
+ } else if ((attr_p->type == SDP_ATTR_SDESCRIPTIONS) ||
+ (attr_p->type == SDP_ATTR_SRTP_CONTEXT)) {
+ SDP_FREE(attr_p->attr.srtp_context.session_parameters);
+ } else if (sdp_attr_is_long_string(attr_p->type)) {
+ SDP_FREE(attr_p->attr.stringp);
+ }
+
+ if (attr_p->type == SDP_ATTR_GROUP) {
+ for (i = 0; i < attr_p->attr.stream_data.num_group_id; i++) {
+ SDP_FREE(attr_p->attr.stream_data.group_ids[i]);
+ }
+ } else if (attr_p->type == SDP_ATTR_MSID_SEMANTIC) {
+ for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
+ SDP_FREE(attr_p->attr.msid_semantic.msids[i]);
+ }
+ }
+
+ /* Now free the actual attribute memory. */
+ SDP_FREE(attr_p);
+
+}
+
+
+/* Function: sdp_find_attr_list
+ * Description: Find the attribute list for the specified level and cap_num.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p Pointer to the SDP to search.
+ * level The level to check for the attribute list.
+ * cap_num The capability number associated with the
+ * attribute list. If none, should be zero.
+ * attr_p Pointer to the attr list pointer. Will be
+ * filled in on return if successful.
+ * fname String function name calling this routine.
+ * Use for printing debug.
+ * Returns: SDP_SUCCESS
+ * SDP_INVALID_MEDIA_LEVEL
+ * SDP_INVALID_CAPABILITY
+ * SDP_FAILURE
+ */
+sdp_result_e sdp_find_attr_list (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_t **attr_p, char *fname)
+{
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *cap_attr_p;
+
+ /* Initialize the attr pointer. */
+ *attr_p = NULL;
+
+ if (cap_num == 0) {
+ /* Find attribute list at the specified level. */
+ if (level == SDP_SESSION_LEVEL) {
+ *attr_p = sdp_p->sess_attrs_p;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ *attr_p = mca_p->media_attrs_p;
+ }
+ } else {
+ /* Find the attr list for the capability specified. */
+ cap_attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (cap_attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s, invalid capability %u at "
+ "level %u specified.", sdp_p->debug_str, fname,
+ (unsigned)cap_num, (unsigned)level);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_CAPABILITY);
+ }
+ cap_p = cap_attr_p->attr.cap_p;
+ *attr_p = cap_p->media_attrs_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Find fmtp inst_num with correct payload value or -1 for failure */
+int sdp_find_fmtp_inst (sdp_t *sdp_p, uint16_t level, uint16_t payload_num)
+{
+ uint16_t attr_count=0;
+ sdp_mca_t *mca_p;
+ sdp_attr_t *attr_p;
+
+ /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (-1);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_FMTP) {
+ attr_count++;
+ if (attr_p->attr.fmtp.payload_num == payload_num) {
+ return (attr_count);
+ }
+ }
+ }
+
+ return (-1);
+
+}
+
+/* Function: sdp_find_attr
+ * Description: Find the specified attribute in an SDP structure.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * attr_type The type of attribute to find.
+ * inst_num The instance num of the attribute to find.
+ * Range should be (1 - max num insts of this
+ * particular type of attribute at this level).
+ * Returns: Pointer to the attribute or NULL if not found.
+ */
+sdp_attr_t *sdp_find_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t inst_num)
+{
+ uint16_t attr_count=0;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *attr_p;
+
+ if (inst_num < 1) {
+ return (NULL);
+ }
+
+ if (cap_num == 0) {
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ } /* Attr is at a media level */
+ } else {
+ /* Attr is a capability X-cpar/cpar attribute. */
+ attr_p = sdp_find_capability(sdp_p, level, cap_num);
+ if (attr_p == NULL) {
+ return (NULL);
+ }
+ cap_p = attr_p->attr.cap_p;
+ /* Now find the specific attribute. */
+ for (attr_p = cap_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == attr_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* Function: sdp_find_capability
+ * Description: Find the specified capability attribute in an SDP structure.
+ * Note: This is not an API for the application but an internal
+ * routine used by the SDP library.
+ * Parameters: sdp_p The SDP handle.
+ * level The level to check for the capability.
+ * cap_num The capability number to locate.
+ * Returns: Pointer to the capability attribute or NULL if not found.
+ */
+sdp_attr_t *sdp_find_capability (sdp_t *sdp_p, uint16_t level, uint8_t cap_num)
+{
+ uint8_t cur_cap_num=0;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *cap_p;
+ sdp_attr_t *attr_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ cur_cap_num += cap_p->num_payloads;
+ if (cap_num <= cur_cap_num) {
+ /* This is the right capability */
+ return (attr_p);
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if ((attr_p->type == SDP_ATTR_X_CAP) ||
+ (attr_p->type == SDP_ATTR_CDSC)) {
+ cap_p = attr_p->attr.cap_p;
+ cur_cap_num += cap_p->num_payloads;
+ if (cap_num <= cur_cap_num) {
+ /* This is the right capability */
+ return (attr_p);
+ }
+ }
+ }
+ }
+
+ /* We didn't find the specified capability. */
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Unable to find specified capability (level %u, "
+ "cap_num %u).", sdp_p->debug_str, (unsigned)level, (unsigned)cap_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+}
+
+/* Function: sdp_attr_valid(sdp_t *sdp_p)
+ * Description: Returns true or false depending on whether the specified
+ * instance of the given attribute has been defined at the
+ * given level.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The attribute type to validate.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_valid (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ if (sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num) == NULL) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+}
+
+/* Function: sdp_attr_line_number(sdp_t *sdp_p)
+ * Description: Returns the line number this attribute appears on.
+ * Only works if the SDP was parsed rather than created
+ * locally.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The attribute type to validate.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: line number, or 0 if an error
+ */
+uint32_t sdp_attr_line_number (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ return 0;
+ } else {
+ return attr_p->line_number;
+ }
+}
+
+static boolean sdp_attr_is_simple_string(sdp_attr_e attr_type) {
+ if ((attr_type != SDP_ATTR_BEARER) &&
+ (attr_type != SDP_ATTR_CALLED) &&
+ (attr_type != SDP_ATTR_CONN_TYPE) &&
+ (attr_type != SDP_ATTR_DIALED) &&
+ (attr_type != SDP_ATTR_DIALING) &&
+ (attr_type != SDP_ATTR_FRAMING) &&
+ (attr_type != SDP_ATTR_MID) &&
+ (attr_type != SDP_ATTR_X_SIDIN) &&
+ (attr_type != SDP_ATTR_X_SIDOUT)&&
+ (attr_type != SDP_ATTR_X_CONFID) &&
+ (attr_type != SDP_ATTR_LABEL) &&
+ (attr_type != SDP_ATTR_ICE_OPTIONS) &&
+ (attr_type != SDP_ATTR_IMAGEATTR) &&
+ (attr_type != SDP_ATTR_SIMULCAST) &&
+ (attr_type != SDP_ATTR_RID)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Function: sdp_attr_get_simple_string
+ * Description: Returns a pointer to a string attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one string parameter. The value is returned as a const
+ * ptr and so cannot be modified by the application. If the
+ * given attribute is not defined, NULL will be returned.
+ * Attributes with a simple string parameter currently include:
+ * bearer, called, connection_type, dialed, dialing, direction
+ * and framing.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The simple string attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to the parameter value.
+ */
+const char *sdp_attr_get_simple_string (sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (!sdp_attr_is_simple_string(attr_type)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple string (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.string_val);
+ }
+}
+
+static boolean sdp_attr_is_long_string(sdp_attr_e attr_type) {
+ return (attr_type == SDP_ATTR_IDENTITY || attr_type == SDP_ATTR_DTLS_MESSAGE);
+}
+
+/* Identical in usage to sdp_attr_get_simple_string() */
+const char *sdp_attr_get_long_string (sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (!sdp_attr_is_long_string(attr_type)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a long string (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.stringp);
+ }
+}
+
+static boolean sdp_attr_is_simple_u32(sdp_attr_e attr_type) {
+ if ((attr_type != SDP_ATTR_EECID) &&
+ (attr_type != SDP_ATTR_PTIME) &&
+ (attr_type != SDP_ATTR_MAXPTIME) &&
+ (attr_type != SDP_ATTR_T38_VERSION) &&
+ (attr_type != SDP_ATTR_T38_MAXBITRATE) &&
+ (attr_type != SDP_ATTR_T38_MAXBUFFER) &&
+ (attr_type != SDP_ATTR_T38_MAXDGRAM) &&
+ (attr_type != SDP_ATTR_X_SQN) &&
+ (attr_type != SDP_ATTR_TC1_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC1_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_TC2_PAYLOAD_BYTES) &&
+ (attr_type != SDP_ATTR_TC2_WINDOW_SIZE) &&
+ (attr_type != SDP_ATTR_FRAMERATE)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Function: sdp_attr_get_simple_u32
+ * Description: Returns an unsigned 32-bit attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one uint32_t parameter. If the given attribute is not defined,
+ * zero will be returned. There is no way for the application
+ * to determine if zero is the actual value or the attribute
+ * wasn't defined, so the application must use the
+ * sdp_attr_valid function to determine this.
+ * Attributes with a simple uint32_t parameter currently include:
+ * eecid, ptime, T38FaxVersion, T38maxBitRate, T38FaxMaxBuffer,
+ * T38FaxMaxDatagram, X-sqn, TC1PayloadBytes, TC1WindowSize,
+ * TC2PayloadBytes, TC2WindowSize, rtcp.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The simple uint32_t attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: uint32_t parameter value.
+ */
+uint32_t sdp_attr_get_simple_u32 (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (!sdp_attr_is_simple_u32(attr_type)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple uint32_t (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.u32_val);
+ }
+}
+
+/* Function: sdp_attr_get_simple_boolean
+ * Description: Returns a boolean attribute parameter. This
+ * routine can only be called for attributes that have just
+ * one boolean parameter. If the given attribute is not defined,
+ * FALSE will be returned. There is no way for the application
+ * to determine if FALSE is the actual value or the attribute
+ * wasn't defined, so the application must use the
+ * sdp_attr_valid function to determine this.
+ * Attributes with a simple boolean parameter currently include:
+ * T38FaxFillBitRemoval, T38FaxTranscodingMMR,
+ * T38FaxTranscodingJBIG, and TMRGwXid.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The simple boolean attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_simple_boolean (sdp_t *sdp_p, sdp_attr_e attr_type,
+ uint16_t level, uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if ((attr_type != SDP_ATTR_T38_FILLBITREMOVAL) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGMMR) &&
+ (attr_type != SDP_ATTR_T38_TRANSCODINGJBIG) &&
+ (attr_type != SDP_ATTR_TMRGWXID)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute type is not a simple boolean (%s)",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type));
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ }
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type),
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.boolean_val);
+ }
+}
+
+/*
+ * sdp_attr_get_maxprate
+ *
+ * This function is used by the application layer to get the packet-rate
+ * within the maxprate attribute.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to set.
+ *
+ * Returns a pointer to a constant char array that stores the packet-rate,
+ * OR null if the attribute does not exist.
+ */
+const char*
+sdp_attr_get_maxprate (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_MAXPRATE, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Attribute %s, level %u instance %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(SDP_ATTR_MAXPRATE),
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.string_val);
+ }
+}
+
+/* Function: sdp_attr_get_t38ratemgmt
+ * Description: Returns the value of the t38ratemgmt attribute
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_T38_UNKNOWN_RATE is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Ratemgmt value.
+ */
+sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_RATEMGMT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38ratemgmt attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_T38_UNKNOWN_RATE);
+ } else {
+ return (attr_p->attr.t38ratemgmt);
+ }
+}
+
+/* Function: sdp_attr_get_t38udpec
+ * Description: Returns the value of the t38udpec attribute
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_T38_UDPEC_UNKNOWN is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: UDP EC value.
+ */
+sdp_t38_udpec_e sdp_attr_get_t38udpec (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_T38_UDPEC, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s t38udpec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_T38_UDPEC_UNKNOWN);
+ } else {
+ return (attr_p->attr.t38udpec);
+ }
+}
+
+/* Function: sdp_get_media_direction
+ * Description: Determines the direction defined for a given level. The
+ * direction will be inactive, sendonly, recvonly, or sendrecv
+ * as determined by the last of these attributes specified at
+ * the given level. If none of these attributes are specified,
+ * the direction will be sendrecv by default.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * Returns: An SDP direction enum value.
+ */
+sdp_direction_e sdp_get_media_direction (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num)
+{
+ sdp_mca_t *mca_p;
+ sdp_attr_t *attr_p;
+ sdp_direction_e direction = SDP_DIRECTION_SENDRECV;
+
+ if (cap_num == 0) {
+ /* Find the pointer to the attr list for this level. */
+ if (level == SDP_SESSION_LEVEL) {
+ attr_p = sdp_p->sess_attrs_p;
+ } else { /* Attr is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (direction);
+ }
+ attr_p = mca_p->media_attrs_p;
+ }
+
+ /* Scan for direction oriented attributes. Last one wins. */
+ for (; attr_p != NULL; attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_INACTIVE) {
+ direction = SDP_DIRECTION_INACTIVE;
+ } else if (attr_p->type == SDP_ATTR_SENDONLY) {
+ direction = SDP_DIRECTION_SENDONLY;
+ } else if (attr_p->type == SDP_ATTR_RECVONLY) {
+ direction = SDP_DIRECTION_RECVONLY;
+ } else if (attr_p->type == SDP_ATTR_SENDRECV) {
+ direction = SDP_DIRECTION_SENDRECV;
+ }
+ }
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid cap_num for media direction.",
+ sdp_p->debug_str);
+ }
+ }
+
+ return (direction);
+}
+
+/* Since there are four different attribute names which all have the same
+ * qos parameters, all of these attributes are accessed through this same
+ * set of APIs. To distinguish between specific attributes, the application
+ * must also pass the attribute type. The attribute must be one of:
+ * SDP_ATTR_QOS, SDP_ATTR_SECURE, SDP_ATTR_X_PC_QOS, and SDP_ATTR_X_QOS.
+ */
+tinybool sdp_validate_qos_attr (sdp_attr_e qos_attr)
+{
+ if ((qos_attr == SDP_ATTR_QOS) ||
+ (qos_attr == SDP_ATTR_SECURE) ||
+ (qos_attr == SDP_ATTR_X_PC_QOS) ||
+ (qos_attr == SDP_ATTR_X_QOS) ||
+ (qos_attr == SDP_ATTR_CURR) ||
+ (qos_attr == SDP_ATTR_DES) ||
+ (qos_attr == SDP_ATTR_CONF)){
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/* Function: sdp_attr_get_qos_strength
+ * Description: Returns the value of the qos attribute strength
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos strength value.
+ */
+sdp_qos_strength_e sdp_attr_get_qos_strength (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified for"
+ "get qos strength.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_STRENGTH_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_STRENGTH_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ return (attr_p->attr.qos.strength);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.strength);
+ default:
+ return SDP_QOS_STRENGTH_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_direction
+ * Description: Returns the value of the qos attribute direction
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_DIR_UNKNOWN is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos direction value.
+ */
+sdp_qos_dir_e sdp_attr_get_qos_direction (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos direction.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_DIR_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_DIR_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_QOS:
+ return (attr_p->attr.qos.direction);
+ case SDP_ATTR_CURR:
+ return (attr_p->attr.curr.direction);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.direction);
+ case SDP_ATTR_CONF:
+ return (attr_p->attr.conf.direction);
+ default:
+ return SDP_QOS_DIR_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_status_type
+ * Description: Returns the value of the qos attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STATUS_TYPE_UNKNOWN is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Qos direction value.
+ */
+sdp_qos_status_types_e sdp_attr_get_qos_status_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos status_type.", sdp_p->debug_str);
+ }
+ return (SDP_QOS_STATUS_TYPE_UNKNOWN);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_QOS_STATUS_TYPE_UNKNOWN);
+ } else {
+ switch (qos_attr) {
+ case SDP_ATTR_CURR:
+ return (attr_p->attr.curr.status_type);
+ case SDP_ATTR_DES:
+ return (attr_p->attr.des.status_type);
+ case SDP_ATTR_CONF:
+ return (attr_p->attr.conf.status_type);
+ default:
+ return SDP_QOS_STATUS_TYPE_UNKNOWN;
+
+ }
+ }
+}
+
+/* Function: sdp_attr_get_qos_confirm
+ * Description: Returns the value of the qos attribute confirm
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_qos_confirm (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ if (sdp_validate_qos_attr(qos_attr) == FALSE) {
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Warning: Invalid QOS attribute specified "
+ "for get qos confirm.", sdp_p->debug_str);
+ }
+ return (FALSE);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.qos.confirm);
+ }
+}
+
+/* Function: sdp_attr_get_curr_type
+ * Description: Returns the value of the curr attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CURR_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: Curr type value.
+ */
+sdp_curr_type_e sdp_attr_get_curr_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_CURR_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.curr.type);
+ }
+}
+
+/* Function: sdp_attr_get_des_type
+ * Description: Returns the value of the des attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_DES_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: DES type value.
+ */
+sdp_des_type_e sdp_attr_get_des_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_DES_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.des.type);
+ }
+}
+
+/* Function: sdp_attr_get_conf_type
+ * Description: Returns the value of the des attribute status_type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_CONF_UNKNOWN_TYPE is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * qos_attr The specific type of qos attribute. May be
+ * qos, secure, X-pc-qos, or X-qos.
+ * inst_num The attribute instance number to check.
+ * Returns: CONF type value.
+ */
+sdp_conf_type_e sdp_attr_get_conf_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_CONF_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.conf.type);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_nettype
+ * Description: Returns the value of the subnet attribute network type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_NT_INVALID is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Nettype value.
+ */
+sdp_nettype_e sdp_attr_get_subnet_nettype (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NT_INVALID);
+ } else {
+ return (attr_p->attr.subnet.nettype);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_addrtype
+ * Description: Returns the value of the subnet attribute address type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_AT_INVALID is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Addrtype value.
+ */
+sdp_addrtype_e sdp_attr_get_subnet_addrtype (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_AT_INVALID);
+ } else {
+ return (attr_p->attr.subnet.addrtype);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_addr
+ * Description: Returns the value of the subnet attribute address
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, NULL is returned. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to address or NULL.
+ */
+const char *sdp_attr_get_subnet_addr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.subnet.addr);
+ }
+}
+
+/* Function: sdp_attr_get_subnet_prefix
+ * Description: Returns the value of the subnet attribute prefix
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_INVALID_PARAM is returned.
+ * Note that this is value is defined to be (-2) and is
+ * different from the return code SDP_INVALID_PARAMETER.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Prefix value or SDP_INVALID_PARAM.
+ */
+int32_t sdp_attr_get_subnet_prefix (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SUBNET, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Subnet attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.subnet.prefix);
+ }
+}
+
+/* Function: sdp_attr_rtpmap_payload_valid
+ * Description: Returns true or false depending on whether an rtpmap
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number of the attribute
+ * found is returned via this param.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_rtpmap_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t *inst_num, uint16_t payload_type)
+{
+ uint16_t i;
+ sdp_attr_t *attr_p;
+ uint16_t num_instances;
+
+ *inst_num = 0;
+
+ if (sdp_attr_num_instances(sdp_p, level, cap_num,
+ SDP_ATTR_RTPMAP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.transport_map.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_rtpmap_payload_type
+ * Description: Returns the value of the rtpmap attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+uint16_t sdp_attr_get_rtpmap_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.",
+ sdp_p->debug_str,
+ (unsigned)level,
+ (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.payload_num);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_encname
+ * Description: Returns a pointer to the value of the encoding name
+ * parameter specified for the given attribute. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application. If the given attribute is not defined, NULL
+ * will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Codec value or SDP_CODEC_INVALID.
+ */
+const char *sdp_attr_get_rtpmap_encname (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.",
+ sdp_p->debug_str,
+ (unsigned)level,
+ (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.transport_map.encname);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_clockrate
+ * Description: Returns the value of the rtpmap attribute clockrate
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Clockrate value.
+ */
+uint32_t sdp_attr_get_rtpmap_clockrate (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.clockrate);
+ }
+}
+
+/* Function: sdp_attr_get_rtpmap_num_chan
+ * Description: Returns the value of the rtpmap attribute num_chan
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of channels param or zero.
+ */
+uint16_t sdp_attr_get_rtpmap_num_chan (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtpmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.num_chan);
+ }
+}
+
+/* Function: sdp_attr_get_ice_attribute
+ * Description: Returns the value of an ice attribute at a given level
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * ice_attrib Returns an ice attrib string
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+
+sdp_result_e sdp_attr_get_ice_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ char **out)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *out = attr_p->attr.ice_attr;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ice attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+}
+
+/* Function: sdp_attr_is_present
+ * Description: Returns a boolean value based on attribute being present or
+ * not
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * attr_type The attribute type.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * Returns:
+ * Boolean value.
+ */
+
+tinybool sdp_attr_is_present (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level,
+ uint8_t cap_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, 1);
+ if (attr_p != NULL) {
+ return (TRUE);
+ }
+ if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
+ CSFLogDebug(logTag, "%s Attribute %s, level %u not found.",
+ sdp_p->debug_str, sdp_get_attr_name(attr_type), level);
+ }
+
+ return (FALSE);
+}
+
+
+
+/* Function: sdp_attr_get_rtcp_mux_attribute
+ * Description: Returns the value of an rtcp-mux attribute at a given level
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * rtcp_mux Returns an rtcp-mux attrib bool
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_rtcp_mux_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ tinybool *rtcp_mux)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *rtcp_mux = attr_p->attr.boolean_val;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-mux attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+}
+
+/* Function: sdp_attr_get_setup_attribute
+ * Description: Returns the value of a setup attribute at a given level
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * setup_type Returns sdp_setup_type_e enum
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_setup_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, sdp_setup_type_e *setup_type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SETUP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag,
+ "%s setup attribute, level %u instance %u not found.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ *setup_type = attr_p->attr.setup;
+ return SDP_SUCCESS;
+}
+
+/* Function: sdp_attr_get_connection_attribute
+ * Description: Returns the value of a connection attribute at a given level
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * connection_type Returns sdp_connection_type_e enum
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_connection_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, sdp_connection_type_e *connection_type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_CONNECTION,
+ inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag,
+ "%s setup attribute, level %u instance %u not found.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ *connection_type = attr_p->attr.connection;
+ return SDP_SUCCESS;
+}
+
+/* Function: sdp_attr_get_dtls_fingerprint_attribute
+ * Description: Returns the value of dtls fingerprint attribute at a given level
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * dtls_fingerprint Returns an dtls fingerprint attrib string
+ * Returns:
+ * SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_SDP_PTR SDP pointer invalid
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_get_dtls_fingerprint_attribute (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num,
+ char **out)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num);
+ if (attr_p != NULL) {
+ *out = attr_p->attr.string_val;
+ return (SDP_SUCCESS);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s dtls fingerprint attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+}
+
+/* Function: sdp_attr_sprtmap_payload_valid
+ * Description: Returns true or false depending on whether an sprtmap
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number of the attribute
+ * found is returned via this param.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_sprtmap_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t *inst_num, uint16_t payload_type)
+{
+ uint16_t i;
+ sdp_attr_t *attr_p;
+ uint16_t num_instances;
+
+ *inst_num = 0;
+
+ if (sdp_attr_num_instances(sdp_p, level, cap_num,
+ SDP_ATTR_SPRTMAP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.transport_map.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_sprtmap_payload_type
+ * Description: Returns the value of the sprtmap attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+uint16_t sdp_attr_get_sprtmap_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.payload_num);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_encname
+ * Description: Returns a pointer to the value of the encoding name
+ * parameter specified for the given attribute. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application. If the given attribute is not defined, NULL
+ * will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Codec value or SDP_CODEC_INVALID.
+ */
+const char *sdp_attr_get_sprtmap_encname (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.transport_map.encname);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_clockrate
+ * Description: Returns the value of the sprtmap attribute clockrate
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Clockrate value.
+ */
+uint32_t sdp_attr_get_sprtmap_clockrate (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.clockrate);
+ }
+}
+
+/* Function: sdp_attr_get_sprtmap_num_chan
+ * Description: Returns the value of the sprtmap attribute num_chan
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of channels param or zero.
+ */
+uint16_t sdp_attr_get_sprtmap_num_chan (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sprtmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.transport_map.num_chan);
+ }
+}
+
+/* Note: The fmtp attribute formats currently handled are:
+ * fmtp:<payload type> <event>,<event>...
+ * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
+ * where "value" is a numeric value > 0
+ * where each event is a single number or a range separated
+ * by a '-'.
+ * Example: fmtp:101 1,3-15,20
+ */
+
+/* Function: tinybool sdp_attr_fmtp_valid(sdp_t *sdp_p)
+ * Description: Returns true or false depending on whether an fmtp
+ * attribute was specified with the given payload value
+ * at the given level. If it was, the instance number of
+ * that attribute is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t *inst_num, uint16_t payload_type)
+{
+ uint16_t i;
+ sdp_attr_t *attr_p;
+ uint16_t num_instances;
+
+ if (sdp_attr_num_instances(sdp_p, level, cap_num,
+ SDP_ATTR_FMTP, &num_instances) != SDP_SUCCESS) {
+ return (FALSE);
+ }
+
+ for (i=1; i <= num_instances; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, i);
+ if ((attr_p != NULL) &&
+ (attr_p->attr.fmtp.payload_num == payload_type)) {
+ *inst_num = i;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/* Function: sdp_attr_get_fmtp_payload_type
+ * Description: Returns the value of the fmtp attribute payload type
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Payload type value.
+ */
+uint16_t sdp_attr_get_fmtp_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.payload_num);
+ }
+}
+
+
+/* Function: sdp_attr_fmtp_is_range_set
+ * Description: Determines if a range of events is set in an fmtp attribute.
+ * The overall range for events is 0-255.
+ * This will return either FULL_MATCH, PARTIAL_MATCH, or NO_MATCH
+ * depending on whether all, some, or none of the specified
+ * events are defined. If the given attribute is not defined,
+ * NO_MATCH will be returned. It is up to the appl to verify
+ * the validity of the attribute before calling this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * low_val Low value of the range. Range is 0-255.
+ * high_val High value of the range.
+ * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH
+ */
+sdp_ne_res_e sdp_attr_fmtp_is_range_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint8_t low_val, uint8_t high_val)
+{
+ uint16_t i;
+ uint32_t mapword;
+ uint32_t bmap;
+ uint32_t num_vals = 0;
+ uint32_t num_vals_set = 0;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_MATCH);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ for (i = low_val; i <= high_val; i++) {
+ num_vals++;
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ if (fmtp_p->bmap[ mapword ] & bmap) {
+ num_vals_set++;
+ }
+ }
+
+ if (num_vals == num_vals_set) {
+ return (SDP_FULL_MATCH);
+ } else if (num_vals_set == 0) {
+ return (SDP_NO_MATCH);
+ } else {
+ return (SDP_PARTIAL_MATCH);
+ }
+}
+
+/* Function: sdp_attr_fmtp_valid
+ * Description: Determines the validity of the events in the fmtp.
+ * The overall range for events is 0-255.
+ * The user passes an event list with valid events supported by Appl.
+ * This routine will do a simple AND comparison and report the result.
+ *
+ * This will return TRUE if ftmp events are valid, and FALSE otherwise.
+ * It is up to the appl to verify the validity of the attribute
+ * before calling this routine.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * appl_maxval Max event value supported by Appl. Range is 0-255.
+ * evt_array Bitmap containing events supported by application.
+ * Returns: TRUE, FALSE
+ */
+tinybool
+sdp_attr_fmtp_valid(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint16_t appl_maxval, uint32_t* evt_array)
+{
+ uint16_t i;
+ uint32_t mapword;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+
+ /* Do quick test. If application max value is lower than fmtp's then error */
+ if (fmtp_p->maxval > appl_maxval)
+ return FALSE;
+
+ /* Ok, events are within range. Now check that only
+ * allowed events have been received
+ */
+ mapword = appl_maxval/SDP_NE_BITS_PER_WORD;
+ for (i=0; i<mapword; i++) {
+ if (fmtp_p->bmap[i] & ~(evt_array[i])) {
+ /* Remote SDP is requesting events not supported by Application */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* Function: sdp_attr_set_fmtp_payload_type
+ * Description: Sets the value of the fmtp attribute payload type parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_type New payload type value.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_set_fmtp_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint16_t payload_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ attr_p->attr.fmtp.payload_num = payload_num;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_range
+ * Description: Get a range of named events for an fmtp attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * bmap The 8 word data array holding the bitmap
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_get_fmtp_range (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint32_t *bmap)
+{
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ memcpy(bmap, fmtp_p->bmap, SDP_NE_NUM_BMAP_WORDS * sizeof(uint32_t) );
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_clear_fmtp_range
+ * Description: Clear a range of named events for an fmtp attribute. The low
+ * value specified must be <= the high value.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * low_val The low value of the range. Range is 0-255
+ * high_val The high value of the range. May be == low.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_clear_fmtp_range (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint8_t low_val, uint8_t high_val)
+{
+ uint16_t i;
+ uint32_t mapword;
+ uint32_t bmap;
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ for (i = low_val; i <= high_val; i++) {
+ mapword = i/SDP_NE_BITS_PER_WORD;
+ bmap = SDP_NE_BIT_0 << (i%32);
+ fmtp_p->bmap[ mapword ] &= ~bmap;
+ }
+ if (high_val > fmtp_p->maxval) {
+ fmtp_p->maxval = high_val;
+ }
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_compare_fmtp_ranges
+ * Description: Compare the named events set of two fmtp attributes. If all
+ * events are the same (either set or not), FULL_MATCH will be
+ * returned. If no events match, NO_MATCH will be returned.
+ * Otherwise PARTIAL_MATCH will be returned. If either attr is
+ * invalid, NO_MATCH will be returned.
+ * Parameters: src_sdp_p The SDP handle returned by sdp_init_description.
+ * dst_sdp_p The SDP handle returned by sdp_init_description.
+ * src_level The level of the src fmtp attribute.
+ * dst_level The level to the dst fmtp attribute.
+ * src_cap_num The capability number of the src attr.
+ * dst_cap_num The capability number of the dst attr.
+ * src_inst_numh The attribute instance of the src attr.
+ * dst_inst_numh The attribute instance of the dst attr.
+ * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH.
+ */
+sdp_ne_res_e sdp_attr_compare_fmtp_ranges (sdp_t *src_sdp_p,sdp_t *dst_sdp_p,
+ uint16_t src_level, uint16_t dst_level,
+ uint8_t src_cap_num, uint8_t dst_cap_num,
+ uint16_t src_inst_num, uint16_t dst_inst_num)
+{
+ uint16_t i,j;
+ uint32_t bmap;
+ uint32_t num_vals_match = 0;
+ sdp_attr_t *src_attr_p;
+ sdp_attr_t *dst_attr_p;
+ sdp_fmtp_t *src_fmtp_p;
+ sdp_fmtp_t *dst_fmtp_p;
+
+ src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num,
+ SDP_ATTR_FMTP, src_inst_num);
+ dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num,
+ SDP_ATTR_FMTP, dst_inst_num);
+ if ((src_attr_p == NULL) || (dst_attr_p == NULL)) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s source or destination fmtp attribute for "
+ "compare not found.", src_sdp_p->debug_str);
+ }
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_MATCH);
+ }
+
+ src_fmtp_p = &(src_attr_p->attr.fmtp);
+ dst_fmtp_p = &(dst_attr_p->attr.fmtp);
+ for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ for (j = 0; j < SDP_NE_BITS_PER_WORD; j++) {
+ bmap = SDP_NE_BIT_0 << j;
+ if ((src_fmtp_p->bmap[i] & bmap) && (dst_fmtp_p->bmap[i] & bmap)) {
+ num_vals_match++;
+ } else if ((!(src_fmtp_p->bmap[i] & bmap)) &&
+ (!(dst_fmtp_p->bmap[i] & bmap))) {
+ num_vals_match++;
+ }
+ }
+ }
+
+ if (num_vals_match == (SDP_NE_NUM_BMAP_WORDS * SDP_NE_BITS_PER_WORD)) {
+ return (SDP_FULL_MATCH);
+ } else if (num_vals_match == 0) {
+ return (SDP_NO_MATCH);
+ } else {
+ return (SDP_PARTIAL_MATCH);
+ }
+}
+
+/* Function: sdp_attr_copy_fmtp_ranges
+ * Description: Copy the named events set for one fmtp attribute to another.
+ * Parameters: src_sdp_p The SDP handle returned by sdp_init_description.
+ * dst_sdp_p The SDP handle returned by sdp_init_description.
+ * src_level The level of the src fmtp attribute.
+ * dst_level The level to the dst fmtp attribute.
+ * src_cap_num The capability number of the src attr.
+ * dst_cap_num The capability number of the dst attr.
+ * src_inst_numh The attribute instance of the src attr.
+ * dst_inst_numh The attribute instance of the dst attr.
+ * Returns: SDP_SUCCESS
+ */
+sdp_result_e sdp_attr_copy_fmtp_ranges (sdp_t *src_sdp_p, sdp_t *dst_sdp_p,
+ uint16_t src_level, uint16_t dst_level,
+ uint8_t src_cap_num, uint8_t dst_cap_num,
+ uint16_t src_inst_num, uint16_t dst_inst_num)
+{
+ uint16_t i;
+ sdp_attr_t *src_attr_p;
+ sdp_attr_t *dst_attr_p;
+ sdp_fmtp_t *src_fmtp_p;
+ sdp_fmtp_t *dst_fmtp_p;
+
+ if (!src_sdp_p || !dst_sdp_p) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num,
+ SDP_ATTR_FMTP, src_inst_num);
+ dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num,
+ SDP_ATTR_FMTP, dst_inst_num);
+ if ((src_attr_p == NULL) || (dst_attr_p == NULL)) {
+ if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s source or destination fmtp attribute for "
+ "copy not found.", src_sdp_p->debug_str);
+ }
+ src_sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ src_fmtp_p = &(src_attr_p->attr.fmtp);
+ dst_fmtp_p = &(dst_attr_p->attr.fmtp);
+ dst_fmtp_p->maxval = src_fmtp_p->maxval;
+ for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) {
+ dst_fmtp_p->bmap[i] = src_fmtp_p->bmap[i];
+ }
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_fmtp_mode
+ * Description: Gets the value of the fmtp attribute mode parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * payload_type payload type.
+ * Returns: mode value or zero if mode attribute not found
+ */
+uint32_t sdp_attr_get_fmtp_mode_for_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint32_t payload_type)
+{
+ uint16_t num_a_lines = 0;
+ int i;
+ sdp_attr_t *attr_p;
+
+ /*
+ * Get number of FMTP attributes for the AUDIO line
+ */
+ (void) sdp_attr_num_instances(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ &num_a_lines);
+ for (i = 0; i < num_a_lines; i++) {
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, (uint16_t) (i + 1));
+ if ((attr_p != NULL) &&
+ (attr_p->attr.fmtp.payload_num == (uint16_t)payload_type)) {
+ if (attr_p->attr.fmtp.fmtp_format == SDP_FMTP_MODE) {
+ return attr_p->attr.fmtp.mode;
+ }
+ }
+ }
+ return 0;
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_fs (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t max_fs)
+{
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_fs > 0) {
+ fmtp_p->max_fs = max_fs;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+sdp_result_e sdp_attr_set_fmtp_max_fr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t max_fr)
+{
+ sdp_attr_t *attr_p;
+ sdp_fmtp_t *fmtp_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ fmtp_p = &(attr_p->attr.fmtp);
+ fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
+
+ if (max_fr > 0) {
+ fmtp_p->max_fr = max_fr;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_average_bitrate
+ * Description: Gets the value of the fmtp attribute- maxaveragebitrate parameter for the OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-br value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, 1);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.maxaveragebitrate;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_usedtx
+ * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: usedtx value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_usedtx (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.usedtx;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_usedtx
+ * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: stereo value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_stereo (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.stereo;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_useinbandfec
+ * Description: Gets the value of the fmtp attribute useinbandfec parameter for the OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: useinbandfec value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_useinbandfec (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.useinbandfec;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_maxcodedaudiobandwidth
+ * Description: Gets the value of the fmtp attribute maxcodedaudiobandwidth parameter for OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: maxcodedaudiobandwidth value.
+ */
+char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.maxcodedaudiobandwidth);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cbr
+ * Description: Gets the value of the fmtp attribute cbr parameter for the OPUS codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: cbr value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_cbr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, tinybool* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = (tinybool)attr_p->attr.fmtp.cbr;
+ return (SDP_SUCCESS);
+ }
+}
+
+uint16_t sdp_attr_get_sctpmap_port(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sctpmap port, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+ } else {
+ return attr_p->attr.sctpmap.port;
+ }
+}
+
+sdp_result_e sdp_attr_get_sctpmap_streams (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP, inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sctpmap streams, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.sctpmap.streams;
+ return (SDP_SUCCESS);
+ }
+}
+
+sdp_result_e sdp_attr_get_sctpmap_protocol (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ char* protocol)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP,
+ inst_num);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s sctpmap, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ sstrncpy(protocol, attr_p->attr.sctpmap.protocol, SDP_MAX_STRING_LEN+1);
+ }
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_fmtp_is_annexb_set
+ * Description: Gives the value of the fmtp attribute annexb type parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_is_annexb_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annexb);
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_annexa_set
+ * Description: Gives the value of the fmtp attribute annexa type parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: TRUE or FALSE.
+ */
+tinybool sdp_attr_fmtp_is_annexa_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annexa);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_bitrate_type
+ * Description: Gets the value of the fmtp attribute bitrate type parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Bitrate type value.
+ */
+int32_t sdp_attr_get_fmtp_bitrate_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.bitrate);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_qcif
+ * Description: Gets the value of the fmtp attribute QCIF type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: QCIF value.
+ */
+int32_t sdp_attr_get_fmtp_qcif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.qcif);
+ }
+}
+/* Function: sdp_attr_get_fmtp_cif
+ * Description: Gets the value of the fmtp attribute CIF type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF value.
+ */
+int32_t sdp_attr_get_fmtp_cif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_sqcif
+ * Description: Gets the value of the fmtp attribute sqcif type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: sqcif value.
+ */
+int32_t sdp_attr_get_fmtp_sqcif (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.sqcif);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cif4
+ * Description: Gets the value of the fmtp attribute CIF4 type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF4 value.
+ */
+int32_t sdp_attr_get_fmtp_cif4 (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif4);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cif16
+ * Description: Gets the value of the fmtp attribute CIF16 type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CIF16 value.
+ */
+
+int32_t sdp_attr_get_fmtp_cif16 (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cif16);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_maxbr
+ * Description: Gets the value of the fmtp attribute MAXBR type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: MAXBR value.
+ */
+int32_t sdp_attr_get_fmtp_maxbr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.maxbr);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_custom_x
+ * Description: Gets the value of the fmtp attribute CUSTOM type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM x value.
+ */
+
+int32_t sdp_attr_get_fmtp_custom_x (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_x);
+ }
+}
+/* Function: sdp_attr_get_fmtp_custom_y
+ * Description: Gets the value of the fmtp attribute custom_y type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM Y-AXIS value.
+ */
+
+int32_t sdp_attr_get_fmtp_custom_y (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_y);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_custom_mpi
+ * Description: Gets the value of the fmtp attribute CUSTOM type parameter
+ * for a given Video codec.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CUSTOM MPI value.
+ */
+
+int32_t sdp_attr_get_fmtp_custom_mpi (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.custom_mpi);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_par_width
+ * Description: Gets the value of the fmtp attribute PAR (width) parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PAR - width value.
+ */
+int32_t sdp_attr_get_fmtp_par_width (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.par_width);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_par_height
+ * Description: Gets the value of the fmtp attribute PAR (height) parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PAR - height value.
+ */
+int32_t sdp_attr_get_fmtp_par_height (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.par_height);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_cpcf
+ * Description: Gets the value of the fmtp attribute- CPCF parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: CPCF value.
+ */
+int32_t sdp_attr_get_fmtp_cpcf (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.cpcf);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_bpp
+ * Description: Gets the value of the fmtp attribute- BPP parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: BPP value.
+ */
+int32_t sdp_attr_get_fmtp_bpp (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.bpp);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_hrd
+ * Description: Gets the value of the fmtp attribute- HRD parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: HRD value.
+ */
+int32_t sdp_attr_get_fmtp_hrd (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.hrd);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_profile
+ * Description: Gets the value of the fmtp attribute- PROFILE parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: PROFILE value.
+ */
+int32_t sdp_attr_get_fmtp_profile (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.profile);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_level
+ * Description: Gets the value of the fmtp attribute- LEVEL parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: LEVEL value.
+ */
+int32_t sdp_attr_get_fmtp_level (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.level);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_interlace
+ * Description: Checks if INTERLACE parameter is set.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE if INTERLACE is present and FALSE if INTERLACE is absent.
+ */
+tinybool sdp_attr_get_fmtp_interlace (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return FALSE;
+ } else {
+ return (attr_p->attr.fmtp.is_interlace);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_pack_mode
+ * Description: Gets the value of the fmtp attribute- packetization-mode parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: packetization-mode value in the range 0 - 2.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_pack_mode (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t *val)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (SDP_INVALID_PACKETIZATION_MODE_VALUE == attr_p->attr.fmtp.packetization_mode) {
+ /* packetization mode unspecified (optional) */
+ *val = SDP_DEFAULT_PACKETIZATION_MODE_VALUE;
+ } else {
+ *val = attr_p->attr.fmtp.packetization_mode;
+ }
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_level_asymmetry_allowed
+ * Description: Gets the value of the fmtp attribute- level-asymmetry-allowed parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: level asymmetry allowed value (0 or 1).
+ */
+
+sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t *val)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.level_asymmetry_allowed;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_profile_id
+ * Description: Gets the value of the fmtp attribute- profile-level-id parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: profile-level-id value.
+ */
+const char* sdp_attr_get_fmtp_profile_id (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.profile_level_id);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_param_sets
+ * Description: Gets the value of the fmtp attribute- parameter-sets parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: parameter-sets value.
+ */
+const char* sdp_attr_get_fmtp_param_sets (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.fmtp.parameter_sets);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_interleaving_depth
+ * Description: Gets the value of the fmtp attribute- interleaving_depth parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: interleaving_depth value
+ */
+
+sdp_result_e sdp_attr_get_fmtp_interleaving_depth (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.interleaving_depth;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_deint_buf_req
+ * Description: Gets the value of the fmtp attribute- deint-buf-req parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: deint-buf-req value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_deint_buf_req (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_REQ_FLAG) {
+ *val = attr_p->attr.fmtp.deint_buf_req;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_don_diff
+ * Description: Gets the value of the fmtp attribute- max-don-diff parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-don-diff value.
+ */
+sdp_result_e sdp_attr_get_fmtp_max_don_diff (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_don_diff;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_init_buf_time
+ * Description: Gets the value of the fmtp attribute- init-buf-time parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: init-buf-time value.
+ */
+sdp_result_e sdp_attr_get_fmtp_init_buf_time (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_INIT_BUF_TIME_FLAG) {
+ *val = attr_p->attr.fmtp.init_buf_time;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_mbps
+ * Description: Gets the value of the fmtp attribute- max-mbps parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-mbps value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_mbps (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_mbps;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_fs
+ * Description: Gets the value of the fmtp attribute- max-fs parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-fs value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_fs (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_fs;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_fr
+ * Description: Gets the value of the fmtp attribute- max-fr parameter
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-fr value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_fr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_fr;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_cpb
+ * Description: Gets the value of the fmtp attribute- max-cpb parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-cpb value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_cpb (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_cpb;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_dpb
+ * Description: Gets the value of the fmtp attribute- max-dpb parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-dpb value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_dpb (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t *val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_dpb;
+ return (SDP_SUCCESS);
+ }
+}
+
+
+/* Function: sdp_attr_get_fmtp_max_br
+ * Description: Gets the value of the fmtp attribute- max-br parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-br value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_max_br (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint32_t* val)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ *val = attr_p->attr.fmtp.max_br;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_redundant_pic_cap
+ * Description: Gets the value of the fmtp attribute- redundant_pic_cap parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: redundant-pic-cap value.
+ */
+tinybool sdp_attr_fmtp_is_redundant_pic_cap (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.redundant_pic_cap);
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_deint_buf_cap
+ * Description: Gets the value of the fmtp attribute- deint-buf-cap parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: deint-buf-cap value.
+ */
+
+sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_CAP_FLAG) {
+ *val = attr_p->attr.fmtp.deint_buf_cap;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_get_fmtp_max_rcmd_nalu_size
+ * Description: Gets the value of the fmtp attribute- max-rcmd-nalu-size parameter for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: max-rcmd-nalu-size value.
+ */
+sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint32_t *val)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ if (attr_p->attr.fmtp.flag & SDP_MAX_RCMD_NALU_SIZE_FLAG) {
+ *val = attr_p->attr.fmtp.max_rcmd_nalu_size;
+ return (SDP_SUCCESS);
+ } else {
+ return (SDP_FAILURE);
+ }
+ }
+}
+
+/* Function: sdp_attr_fmtp_is_parameter_add
+ * Description: Gets the value of the fmtp attribute- parameter-add for H.264 codec
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: TRUE/FALSE ( parameter-add is boolean)
+ */
+tinybool sdp_attr_fmtp_is_parameter_add (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ /* Both 1 and SDP_FMTP_UNUSED (parameter not present) should be
+ * treated as TRUE, per RFC 3984, page 45 */
+ return (attr_p->attr.fmtp.parameter_add != 0);
+ }
+}
+
+/****** Following functions are get routines for Annex values
+ * For each Annex support, the get routine will return the boolean TRUE/FALSE
+ * Some Annexures for Video codecs have values defined . In those cases,
+ * (e.g Annex K, P ) , the return values are not boolean.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Annex value
+ */
+
+tinybool sdp_attr_get_fmtp_annex_d (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_d);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_f (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_f);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_i (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_i);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_j (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_j);
+ }
+}
+
+tinybool sdp_attr_get_fmtp_annex_t (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.fmtp.annex_t);
+ }
+}
+
+int32_t sdp_attr_get_fmtp_annex_k_val (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_k_val);
+ }
+}
+
+int32_t sdp_attr_get_fmtp_annex_n_val (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_n_val);
+ }
+}
+
+int32_t sdp_attr_get_fmtp_annex_p_picture_resize (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_p_val_picture_resize);
+ }
+}
+
+int32_t sdp_attr_get_fmtp_annex_p_warp (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ } else {
+ return (attr_p->attr.fmtp.annex_p_val_warp);
+ }
+}
+
+/* Function: sdp_attr_fmtp_get_fmtp_format
+ * Description: Gives the value of the fmtp attribute fmtp_format
+ * type parameter
+ * for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ *
+ *
+ * Returns: Enum type sdp_fmtp_format_type_e
+ */
+sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s fmtp attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_FMTP_UNKNOWN_TYPE);
+ } else {
+ return (attr_p->attr.fmtp.fmtp_format);
+ }
+}
+
+/* Function: sdp_attr_get_pccodec_num_payload_types
+ * Description: Returns the number of payload types specified for the
+ * given X-pc-codec attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types.
+ */
+uint16_t sdp_attr_get_pccodec_num_payload_types (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.pccodec.num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_pccodec_payload_type
+ * Description: Returns the value of the specified payload type for the
+ * given X-pc-codec attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to get. Range is (1 -
+ * max num payloads).
+ * Returns: Payload type.
+ */
+uint16_t sdp_attr_get_pccodec_payload_type (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint16_t payload_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ if ((payload_num < 1) ||
+ (payload_num > attr_p->attr.pccodec.num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u, "
+ "invalid payload number %u requested.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num, (unsigned)payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ return (attr_p->attr.pccodec.payload_type[payload_num-1]);
+ }
+ }
+}
+
+/* Function: sdp_attr_add_pccodec_payload_type
+ * Description: Add a new value to the list of payload types specified for
+ * the given X-pc-codec attribute. The payload type will be
+ * added to the end of the list so these values should be added
+ * in the order they will be displayed within the attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * payload_type The payload type to add.
+ * Returns: SDP_SUCCESS Payload type was added successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e sdp_attr_add_pccodec_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ uint16_t payload_type)
+{
+ uint16_t payload_num;
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC,
+ inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-pc-codec attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ payload_num = attr_p->attr.pccodec.num_payloads++;
+ attr_p->attr.pccodec.payload_type[payload_num] = payload_type;
+ return (SDP_SUCCESS);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_first_cap_num
+ * Description: Gets the first capability number valid for the specified
+ * X-cap attribute instance. If the capability is not
+ * defined, zero is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the capability.
+ * inst_num The X-cap instance number to check.
+ * Returns: Capability number or zero.
+ */
+uint16_t sdp_attr_get_xcap_first_cap_num (sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ uint16_t cap_num=1;
+ uint16_t attr_count=0;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_X_CAP) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_X_CAP) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } /* Attr is at a media level */
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+}
+
+/* Function: sdp_attr_get_xcap_media_type
+ * Description: Returns the media type specified for the given X-cap
+ * attribute. If the given attribute is not defined,
+ * SDP_MEDIA_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_attr_get_xcap_media_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIA_INVALID);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->media);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_transport_type
+ * Description: Returns the transport type specified for the given X-cap
+ * attribute. If the given attribute is not defined,
+ * SDP_TRANSPORT_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_attr_get_xcap_transport_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP,
+ inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->transport);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified X-cap attribute. If the attribute is invalid,
+ * zero will be returned. Application must validate the
+ * attribute line before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types or zero.
+ */
+uint16_t sdp_attr_get_xcap_num_payload_types (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ return (cap_p->num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_xcap_payload_type
+ * Description: Returns the payload type of the specified payload for the
+ * X-cap attribute line. If the attr line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the X-cap attr before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to retrieve. Range is
+ * (1 - max num payloads).
+ * Returns: Payload type or zero.
+ */
+uint16_t sdp_attr_get_xcap_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cap_p = attr_p->attr.cap_p;
+ if ((payload_num < 1) ||
+ (payload_num > cap_p->num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u, "
+ "payload num %u invalid.", sdp_p->debug_str,
+ (unsigned)level, (unsigned)inst_num, (unsigned)payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *indicator = cap_p->payload_indicator[payload_num-1];
+ return (cap_p->payload_type[payload_num-1]);
+ }
+ }
+}
+
+
+/* Function: sdp_attr_add_xcap_payload_type
+ * Description: Add a new payload type for the X-cap attribute line
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_type The new payload type.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_add_xcap_payload_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cap_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-cap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cap_p = attr_p->attr.cap_p;
+ cap_p->payload_indicator[cap_p->num_payloads] = indicator;
+ cap_p->payload_type[cap_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_cdsc_first_cap_num
+ * Description: Gets the first capability number valid for the specified
+ * CDSC attribute instance. If the capability is not
+ * defined, zero is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the capability.
+ * inst_num The CDSC instance number to check.
+ * Returns: Capability number or zero.
+ */
+uint16_t sdp_attr_get_cdsc_first_cap_num(sdp_t *sdp_p, uint16_t level, uint16_t inst_num)
+{
+ uint16_t cap_num=1;
+ uint16_t attr_count=0;
+ sdp_attr_t *attr_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_CDSC) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } else { /* Capability is at a media level */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p != NULL;
+ attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_CDSC) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (cap_num);
+ } else {
+ cap_num += attr_p->attr.cap_p->num_payloads;
+ }
+ }
+ }
+ } /* Attr is at a media level */
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+}
+
+/* Function: sdp_attr_get_cdsc_media_type
+ * Description: Returns the media type specified for the given CDSC
+ * attribute. If the given attribute is not defined,
+ * SDP_MEDIA_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_MEDIA_INVALID.
+ */
+sdp_media_e sdp_attr_get_cdsc_media_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIA_INVALID);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->media);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_transport_type
+ * Description: Returns the transport type specified for the given CDSC
+ * attribute. If the given attribute is not defined,
+ * SDP_TRANSPORT_INVALID is returned.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Media type or SDP_TRANSPORT_INVALID.
+ */
+sdp_transport_e sdp_attr_get_cdsc_transport_type(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC,
+ inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_TRANSPORT_INVALID);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->transport);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_num_payload_types
+ * Description: Returns the number of payload types associated with the
+ * specified CDSC attribute. If the attribute is invalid,
+ * zero will be returned. Application must validate the
+ * attribute line before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of payload types or zero.
+ */
+uint16_t sdp_attr_get_cdsc_num_payload_types (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ return (cdsc_p->num_payloads);
+ }
+}
+
+/* Function: sdp_attr_get_cdsc_payload_type
+ * Description: Returns the payload type of the specified payload for the
+ * CDSC attribute line. If the attr line or payload number is
+ * invalid, zero will be returned. Application must validate
+ * the CDSC attr before using this routine.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_num The payload number to retrieve. Range is
+ * (1 - max num payloads).
+ * Returns: Payload type or zero.
+ */
+uint16_t sdp_attr_get_cdsc_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_num,
+ sdp_payload_ind_e *indicator)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ cdsc_p = attr_p->attr.cap_p;
+ if ((payload_num < 1) ||
+ (payload_num > cdsc_p->num_payloads)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u, "
+ "payload num %u invalid.", sdp_p->debug_str,
+ (unsigned)level, (unsigned)inst_num, (unsigned)payload_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *indicator = cdsc_p->payload_indicator[payload_num-1];
+ return (cdsc_p->payload_type[payload_num-1]);
+ }
+ }
+}
+
+/* Function: sdp_attr_add_cdsc_payload_type
+ * Description: Add a new payload type for the CDSC attribute line
+ * specified. The new payload type will be added at the end
+ * of the payload type list.
+ * Note: cap_num is not specified. It must be zero.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * payload_type The new payload type.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER
+ */
+sdp_result_e sdp_attr_add_cdsc_payload_type (sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num, uint16_t payload_type,
+ sdp_payload_ind_e indicator)
+{
+ sdp_attr_t *attr_p;
+ sdp_mca_t *cdsc_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num);
+ if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s CDSC attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ cdsc_p = attr_p->attr.cap_p;
+ cdsc_p->payload_indicator[cdsc_p->num_payloads] = indicator;
+ cdsc_p->payload_type[cdsc_p->num_payloads++] = payload_type;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_media_dynamic_payload_valid
+ * Description: Checks if the dynamic payload type passed in is defined
+ * on the media line m_line
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * payload_type Payload type to be checked
+ *
+ * Returns: TRUE or FALSE. Returns TRUE if payload type is defined on the
+ * media line, else returns FALSE
+ */
+
+tinybool sdp_media_dynamic_payload_valid (sdp_t *sdp_p, uint16_t payload_type,
+ uint16_t m_line)
+{
+ uint16_t p_type,m_ptype;
+ ushort num_payload_types;
+ sdp_payload_ind_e ind;
+ tinybool payload_matches = FALSE;
+ tinybool result = TRUE;
+
+ if ((payload_type < SDP_MIN_DYNAMIC_PAYLOAD) ||
+ (payload_type > SDP_MAX_DYNAMIC_PAYLOAD)) {
+ return FALSE;
+ }
+
+ num_payload_types =
+ sdp_get_media_num_payload_types(sdp_p, m_line);
+
+ for(p_type=1; p_type <=num_payload_types;p_type++){
+
+ m_ptype = (uint16_t)sdp_get_media_payload_type(sdp_p,
+ m_line, p_type, &ind);
+ if (payload_type == m_ptype) {
+ payload_matches = TRUE;
+ break;
+ }
+
+ }
+
+ if (!payload_matches) {
+ return FALSE;
+ }
+
+ return (result);
+
+}
+
+/* Function: sdp_attr_get_rtr_confirm
+ * Description: Returns the value of the rtr attribute confirm
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_rtr_confirm (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTR, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s %s attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str,
+ sdp_get_attr_name(SDP_ATTR_RTR), (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.rtr.confirm);
+ }
+}
+
+
+
+sdp_mediadir_role_e sdp_attr_get_comediadir_role (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_DIRECTION, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Comediadir role attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_MEDIADIR_ROLE_UNKNOWN);
+ } else {
+ return (attr_p->attr.comediadir.role);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_enabled
+ * Description: Returns the value of the silencesupp attribute enable
+ * parameter specified for the given attribute. Returns TRUE if
+ * the confirm parameter is specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Boolean value.
+ */
+tinybool sdp_attr_get_silencesupp_enabled (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceSuppEnable attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (FALSE);
+ } else {
+ return (attr_p->attr.silencesupp.enabled);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_timer
+ * Description: Returns the value of the silencesupp attribute timer
+ * parameter specified for the given attribute. null_ind
+ * is set to TRUE if no value was specified, but instead the
+ * null "-" value was specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 16-bit timer value
+ * boolean null_ind
+ */
+uint16_t sdp_attr_get_silencesupp_timer (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ tinybool *null_ind)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silenceTimer attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *null_ind = attr_p->attr.silencesupp.timer_null;
+ return (attr_p->attr.silencesupp.timer);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_pref
+ * Description: Sets the silencesupp supppref value
+ * If this parameter is TRUE, the confirm parameter will be
+ * specified when the SDP description is built.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * confirm New qos confirm parameter.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref (sdp_t *sdp_p,
+ uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence suppPref attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SILENCESUPP_PREF_UNKNOWN);
+ } else {
+ return (attr_p->attr.silencesupp.pref);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_siduse
+ * Description: Returns the value of the silencesupp attribute siduse
+ * parameter specified for the given attribute. If the given
+ * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is
+ * returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: silencesupp siduse enum.
+ */
+sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence sidUse attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_SILENCESUPP_SIDUSE_UNKNOWN);
+ } else {
+ return (attr_p->attr.silencesupp.siduse);
+ }
+}
+
+/* Function: sdp_attr_get_silencesupp_fxnslevel
+ * Description: Returns the value of the silencesupp attribute fxns
+ * (fixed noise) parameter specified for the given attribute.
+ * null_ind is set to TRUE if no value was specified,
+ * but instead the null "-" value was specified.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 7-bit fxns value
+ * boolean null_ind
+ */
+uint8_t sdp_attr_get_silencesupp_fxnslevel (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ tinybool *null_ind)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SILENCESUPP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s silence fxnslevel attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ *null_ind = attr_p->attr.silencesupp.fxnslevel_null;
+ return (attr_p->attr.silencesupp.fxnslevel);
+ }
+}
+
+/* Function: sdp_attr_get_mptime_num_intervals
+ * Description: Returns the number of intervals specified for the
+ * given mptime attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Number of intervals.
+ */
+uint16_t sdp_attr_get_mptime_num_intervals (
+ sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num) {
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p != NULL) {
+ return attr_p->attr.mptime.num_intervals;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u not found.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+}
+
+/* Function: sdp_attr_get_mptime_interval
+ * Description: Returns the value of the specified interval for the
+ * given mptime attribute. If the given attribute is not
+ * defined, zero is returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * interval_num The interval number to get. Range is (1 -
+ * max num payloads).
+ * Returns: Interval.
+ */
+uint16_t sdp_attr_get_mptime_interval (
+ sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num,
+ uint16_t interval_num) {
+
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+ }
+
+ if ((interval_num<1) || (interval_num>attr_p->attr.mptime.num_intervals)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u, "
+ "invalid interval number %u requested.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num, (unsigned)interval_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0;
+ }
+
+ return attr_p->attr.mptime.intervals[interval_num-1];
+}
+
+/* Function: sdp_attr_add_mptime_interval
+ * Description: Add a new value to the list of intervals specified for
+ * the given mptime attribute. The interval will be
+ * added to the end of the list so these values should be added
+ * in the order they will be displayed within the attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mp_interval The interval to add.
+ * Returns: SDP_SUCCESS Interval was added successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ * SDP_INVALID_SDP_PTR Supplied SDP pointer is invalid
+ */
+sdp_result_e sdp_attr_add_mptime_interval (
+ sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num,
+ uint16_t mp_interval) {
+
+ uint16_t interval_num;
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ interval_num = attr_p->attr.mptime.num_intervals;
+ if (interval_num>=SDP_MAX_PAYLOAD_TYPES) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s mptime attribute, level %u instance %u "
+ "exceeds maximum length.",
+ sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ attr_p->attr.mptime.intervals[interval_num] = mp_interval;
+ ++attr_p->attr.mptime.num_intervals;
+ return SDP_SUCCESS;
+}
+
+
+
+/* Function: sdp_get_group_attr
+ * Description: Returns the attribute parameter from the a=group:<>
+ * line. If no attrib has been set ,
+ * SDP_GROUP_ATTR_UNSUPPORTED will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: Valid attrib value or SDP_GROUP_ATTR_UNSUPPORTED.
+ */
+sdp_group_attr_e sdp_get_group_attr (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Group (a= group line) attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_GROUP_ATTR_UNSUPPORTED);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr field is :%s ",
+ sdp_p->debug_str,
+ sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr) );
+ }
+ return (attr_p->attr.stream_data.group_attr);
+ }
+}
+
+/* Function: sdp_get_group_num_id
+ * Description: Returns the number of ids from the a=group:<> line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * Returns: Num of group ids present or 0 if there is an error.
+ */
+uint16_t sdp_get_group_num_id (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s a=group level attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (0);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr - num of ids is :%u ",
+ sdp_p->debug_str,
+ (unsigned)attr_p->attr.stream_data.num_group_id);
+ }
+ }
+ return (attr_p->attr.stream_data.num_group_id);
+}
+
+/* Function: sdp_get_group_id
+ * Description: Returns the group id from the a=group:<> line.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level SDP_SESSION_LEVEL
+ * id_num Number of the id to retrieve. The range is (1 -
+ * SDP_MAX_GROUP_STREAM_ID)
+ * Returns: Value of the group id at the index specified or
+ * NULL if an error
+ */
+const char* sdp_get_group_id (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num, uint16_t id_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_GROUP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s a=group level attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream data group attr - num of ids is :%u ",
+ sdp_p->debug_str,
+ (unsigned)attr_p->attr.stream_data.num_group_id);
+ }
+ if ((id_num < 1) || (id_num > attr_p->attr.stream_data.num_group_id)) {
+ return (NULL);
+ }
+ }
+ return (attr_p->attr.stream_data.group_ids[id_num-1]);
+}
+
+/* Function: sdp_attr_get_x_sidin
+ * Description: Returns the attribute parameter from the a=X-sidin:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to sidin or NULL.
+ */
+const char* sdp_attr_get_x_sidin (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDIN, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidin attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-sidin attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_sidin);
+ }
+ return (attr_p->attr.stream_data.x_sidin);
+ }
+}
+
+/* Function: sdp_attr_get_x_sidout
+ * Description: Returns the attribute parameter from the a=X-sidout:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to sidout or NULL.
+ */
+const char* sdp_attr_get_x_sidout (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_SIDOUT, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-sidout attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-sidout attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_sidout);
+ }
+ return (attr_p->attr.stream_data.x_sidout);
+ }
+}
+
+/* Function: sdp_attr_get_x_confid
+ * Description: Returns the attribute parameter from the a=X-confid:<>
+ * line. If no attrib has been set NULL will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level media level index
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to confid or NULL.
+ */
+const char* sdp_attr_get_x_confid (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_X_CONFID, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s X-confid attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Stream X-confid attr field is :%s ",
+ sdp_p->debug_str,
+ attr_p->attr.stream_data.x_confid);
+ }
+ return (attr_p->attr.stream_data.x_confid);
+ }
+}
+
+/* Function: sdp_get_source_filter_mode
+ * Description: Gets the filter mode in internal representation
+ * Parameters: sdp_p The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * Returns: Filter mode (incl/excl/not present)
+ */
+sdp_src_filter_mode_e
+sdp_get_source_filter_mode (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u, "
+ "instance %u not found", sdp_p->debug_str,
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_FILTER_MODE_NOT_PRESENT);
+ }
+ return (attr_p->attr.source_filter.mode);
+}
+
+/* Function: sdp_get_filter_destination_attributes
+ * Description: Gets the destination address parameters
+ * Parameters: Network type (optional), destination address type
+ * (optional), and destination address (mandatory) variables
+ * which gets updated.
+ * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR
+ */
+sdp_result_e
+sdp_get_filter_destination_attributes (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, sdp_nettype_e *nettype,
+ sdp_addrtype_e *addrtype,
+ char *dest_addr)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (nettype) {
+ *nettype = attr_p->attr.source_filter.nettype;
+ }
+ if (addrtype) {
+ *addrtype = attr_p->attr.source_filter.addrtype;
+ }
+ sstrncpy(dest_addr, attr_p->attr.source_filter.dest_addr,
+ SDP_MAX_STRING_LEN+1);
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_get_filter_source_address_count
+ * Description: Gets the number of source addresses in the list
+ * Parameters: sdp_p The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * Returns: Source-list count
+ */
+
+int32_t
+sdp_get_filter_source_address_count (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_VALUE);
+ }
+ return (attr_p->attr.source_filter.num_src_addr);
+}
+
+/* Function: sdp_get_filter_source_address
+ * Description: Gets one of the source address that is indexed by the user
+ * Parameters: sdp_p The SDP handle which contains the attributes
+ * level SDP_SESSION_LEVEL/m-line number
+ * inst_num The attribute instance number
+ * src_addr_id User provided index (value in range between
+ * 0 to (SDP_MAX_SRC_ADDR_LIST-1) which obtains
+ * the source addr corresponding to it.
+ * src_addr The user provided variable which gets updated
+ * with source address corresponding to the index
+ */
+sdp_result_e
+sdp_get_filter_source_address (sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num, uint16_t src_addr_id,
+ char *src_addr)
+{
+ sdp_attr_t *attr_p;
+
+ src_addr[0] = '\0';
+
+ if (src_addr_id >= SDP_MAX_SRC_ADDR_LIST) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SOURCE_FILTER, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s Source filter attribute, level %u instance %u "
+ "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ if (src_addr_id >= attr_p->attr.source_filter.num_src_addr) {
+ return (SDP_INVALID_PARAMETER);
+ }
+ sstrncpy(src_addr, attr_p->attr.source_filter.src_list[src_addr_id],
+ SDP_MAX_STRING_LEN+1);
+
+ return (SDP_SUCCESS);
+}
+
+sdp_rtcp_unicast_mode_e
+sdp_get_rtcp_unicast_mode(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_RTCP_UNICAST, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s RTCP Unicast attribute, level %u, "
+ "instance %u not found", sdp_p->debug_str,
+ (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_RTCP_UNICAST_MODE_NOT_PRESENT);
+ }
+ return ((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val);
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_tag
+ * Description: Returns the value of the sdescriptions tag
+ * parameter specified for the given attribute.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: Tag value or SDP_INVALID_VALUE (-2) if error encountered.
+ */
+
+int32_t
+sdp_attr_get_sdescriptions_tag (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute tag, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_VALUE;
+ } else {
+ return attr_p->attr.srtp_context.tag;
+ }
+}
+
+/* Function: sdp_attr_get_sdescriptions_crypto_suite
+ * Description: Returns the value of the sdescriptions crypto suite
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the suite. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SRTP_UNKNOWN_CRYPTO_SUITE is returned if an error was
+ * encountered otherwise the crypto suite is returned.
+ */
+
+sdp_srtp_crypto_suite_t
+sdp_attr_get_sdescriptions_crypto_suite (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* There's no version 2 so now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute suite, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SRTP_UNKNOWN_CRYPTO_SUITE;
+ }
+ }
+
+ return attr_p->attr.srtp_context.suite;
+
+}
+
+/* Function: sdp_attr_get_sdescriptions_key
+ * Description: Returns the value of the sdescriptions master key
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the key. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or master key salt string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_key (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute key, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*)attr_p->attr.srtp_context.master_key;
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_salt
+ * Description: Returns the value of the sdescriptions master salt
+ * parameter specified for the given attribute. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the salt. If it's not,
+ * try to find the version 9. This assumes you cannot have both
+ * versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or master key salt string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_salt (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute salt, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*) attr_p->attr.srtp_context.master_salt;
+
+}
+
+
+
+/* Function: sdp_attr_get_sdescriptions_lifetime
+ * Description: Returns the value of the sdescriptions lifetime
+ * parameter specified for the given attribute.Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the lifetime. If it's
+ * not, try to find the version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if error encountered or lifetime string
+ */
+
+const char*
+sdp_attr_get_sdescriptions_lifetime (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first. */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute lifetime, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return (char*)attr_p->attr.srtp_context.master_key_lifetime;
+
+}
+
+/* Function: sdp_attr_get_sdescriptions_mki
+ * Description: Returns the value of the sdescriptions MKI value and length
+ * parameter of the specified attribute instance. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return the MKI. If it's
+ * not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * mki_value application provided pointer that on exit
+ * is set to the MKI value string if one exists.
+ * mki_length application provided pointer that on exit
+ * is set to the MKI length if one exists.
+ * Returns: SDP_SUCCESS no errors encountered otherwise sdp error
+ * based upon the specific error.
+ */
+
+sdp_result_e
+sdp_attr_get_sdescriptions_mki (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num,
+ const char **mki_value,
+ uint16_t *mki_length)
+{
+ sdp_attr_t *attr_p;
+
+ *mki_value = NULL;
+ *mki_length = 0;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+ }
+
+ *mki_value = (char*)attr_p->attr.srtp_context.mki;
+ *mki_length = attr_p->attr.srtp_context.mki_size_bytes;
+ return SDP_SUCCESS;
+
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_session_params
+ * Description: Returns the unparsed session parameters string. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return session parameters. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: NULL if no session parameters were received in the sdp,
+ * otherwise returns a pointer to the start of the session
+ * parameters string. Note that the calling function should
+ * not free the returned pointer.
+ */
+
+const char*
+sdp_attr_get_sdescriptions_session_params (sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute session params, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return NULL;
+ }
+ }
+
+ return attr_p->attr.srtp_context.session_parameters;
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_key_size
+ * Description: Returns the master key size. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return key size. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was
+ * encountered, otherwise key size.
+ */
+
+unsigned char
+sdp_attr_get_sdescriptions_key_size (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.master_key_size_bytes;
+
+}
+
+
+/* Function: sdp_attr_get_sdescriptions_salt_size
+ * Description: Returns the salt key size. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return salt size. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was
+ * encountered, otherwise salt size.
+ */
+
+unsigned char
+sdp_attr_get_sdescriptions_salt_size (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num)
+{
+
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.master_salt_size_bytes;
+
+}
+
+
+/* Function: sdp_attr_get_srtp_crypto_selection_flags
+ * Description: Returns the selection flags. Note that
+ * this is a common api for both version 2 and version 9
+ * sdescriptions. It has no knowledge which version is being
+ * used so it will first try to find if a version 2 sdescriptions
+ * attribute is present. If it is, return selection flags. If
+ * it's not, try to find version 9. This assumes you cannot have
+ * both versions in the same SDP.
+ * Currently only necessary for MGCP.
+ *
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * cap_num The capability number associated with the
+ * attribute if any. If none, should be zero.
+ * inst_num The attribute instance number to check.
+ * Returns: 0 (SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN) if error was
+ * encountered, otherwise selection flags.
+ */
+
+unsigned long
+sdp_attr_get_srtp_crypto_selection_flags (sdp_t *sdp_p,
+ uint16_t level,
+ uint8_t cap_num,
+ uint16_t inst_num)
+{
+
+
+ sdp_attr_t *attr_p;
+
+ /* Try version 2 first */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SRTP_CONTEXT, inst_num);
+
+ if (attr_p == NULL) {
+ /* Couldn't find version 2 now try version 9 */
+ attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_SDESCRIPTIONS, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s srtp attribute MKI, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN;
+ }
+ }
+
+ return attr_p->attr.srtp_context.selection_flags;
+
+}
+
+
+
+/* Function: sdp_find_rtcp_fb_attr
+ * Description: Helper to find the nth instance of a rtcp-fb attribute of
+ * the specified feedback type.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * fb_type The feedback type to look for.
+ * inst_num The attribute instance number to check.
+ * Returns: Pointer to the attribute, or NULL if not found.
+ */
+
+sdp_attr_t *
+sdp_find_rtcp_fb_attr (sdp_t *sdp_p,
+ uint16_t level,
+ uint16_t payload_type,
+ sdp_rtcp_fb_type_e fb_type,
+ uint16_t inst_num)
+{
+ uint16_t attr_count=0;
+ sdp_mca_t *mca_p;
+ sdp_attr_t *attr_p;
+
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (!mca_p) {
+ return (NULL);
+ }
+ for (attr_p = mca_p->media_attrs_p; attr_p; attr_p = attr_p->next_p) {
+ if (attr_p->type == SDP_ATTR_RTCP_FB &&
+ (attr_p->attr.rtcp_fb.payload_num == payload_type ||
+ attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) &&
+ attr_p->attr.rtcp_fb.feedback_type == fb_type) {
+ attr_count++;
+ if (attr_count == inst_num) {
+ return (attr_p);
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Function: sdp_attr_get_rtcp_fb_ack
+ * Description: Returns the value of the rtcp-fb:...ack attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * inst_num The attribute instance number to check.
+ * Returns: ACK type (SDP_RTCP_FB_ACK_NOT_FOUND if not present)
+ */
+sdp_rtcp_fb_ack_type_e
+sdp_attr_get_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type,
+ SDP_RTCP_FB_ACK, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)payload_type, (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_RTCP_FB_ACK_NOT_FOUND;
+ }
+ return (attr_p->attr.rtcp_fb.param.ack);
+}
+
+/* Function: sdp_attr_get_rtcp_fb_nack
+ * Description: Returns the value of the rtcp-fb:...nack attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * inst_num The attribute instance number to check.
+ * Returns: NACK type (SDP_RTCP_FB_NACK_NOT_FOUND if not present)
+ */
+sdp_rtcp_fb_nack_type_e
+sdp_attr_get_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type,
+ SDP_RTCP_FB_NACK, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)payload_type, (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_RTCP_FB_NACK_NOT_FOUND;
+ }
+ return (attr_p->attr.rtcp_fb.param.nack);
+}
+
+/* Function: sdp_attr_get_rtcp_fb_trr_int
+ * Description: Returns the value of the rtcp-fb:...trr-int attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * inst_num The attribute instance number to check.
+ * Returns: trr-int interval (0xFFFFFFFF if not found)
+ */
+uint32_t
+sdp_attr_get_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level,
+ uint16_t payload_type, uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type,
+ SDP_RTCP_FB_TRR_INT, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)payload_type, (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0xFFFFFFFF;
+ }
+ return (attr_p->attr.rtcp_fb.param.trr_int);
+}
+
+/* Function: sdp_attr_get_rtcp_fb_remb_enabled
+ * Description: Returns true if rtcp-fb:...goog-remb attribute exists
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * Returns: true if rtcp-fb:...goog-remb exists
+ */
+tinybool
+sdp_attr_get_rtcp_fb_remb_enabled(sdp_t *sdp_p,
+ uint16_t level,
+ uint16_t payload_type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type,
+ SDP_RTCP_FB_REMB,
+ 1); // always check for 1st instance
+ return (attr_p? TRUE : FALSE); // either exists or not
+}
+
+/* Function: sdp_attr_get_rtcp_fb_ccm
+ * Description: Returns the value of the rtcp-fb:...ccm attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * payload_type The payload to get the attribute for
+ * inst_num The attribute instance number to check.
+ * Returns: CCM type (SDP_RTCP_FB_CCM_NOT_FOUND if not present)
+ */
+sdp_rtcp_fb_ccm_type_e
+sdp_attr_get_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type,
+ SDP_RTCP_FB_CCM, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)payload_type, (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_RTCP_FB_CCM_NOT_FOUND;
+ }
+ return (attr_p->attr.rtcp_fb.param.ccm);
+}
+
+/* Function: sdp_attr_set_rtcp_fb_ack
+ * Description: Sets the value of an rtcp-fb:...ack attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * payload_type The value to set the payload type to for
+ * this attribute. Can be SDP_ALL_PAYLOADS.
+ * inst_num The attribute instance number to check.
+ * type The ack type to indicate
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_ack_type_e type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp_fb ack attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.rtcp_fb.payload_num = payload_type;
+ attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_ACK;
+ attr_p->attr.rtcp_fb.param.ack = type;
+ attr_p->attr.rtcp_fb.extra[0] = '\0';
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_attr_set_rtcp_fb_nack
+ * Description: Sets the value of an rtcp-fb:...nack attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * payload_type The value to set the payload type to for
+ * this attribute. Can be SDP_ALL_PAYLOADS.
+ * inst_num The attribute instance number to check.
+ * type The nack type to indicate
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_nack_type_e type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp_fb nack attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.rtcp_fb.payload_num = payload_type;
+ attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_NACK;
+ attr_p->attr.rtcp_fb.param.nack = type;
+ attr_p->attr.rtcp_fb.extra[0] = '\0';
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_rtcp_fb_trr_int
+ * Description: Sets the value of an rtcp-fb:...trr-int attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * payload_type The value to set the payload type to for
+ * this attribute. Can be SDP_ALL_PAYLOADS.
+ * inst_num The attribute instance number to check.
+ * interval The interval time to indicate
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type,
+ uint16_t inst, uint32_t interval)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp_fb trr-int attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.rtcp_fb.payload_num = payload_type;
+ attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_TRR_INT;
+ attr_p->attr.rtcp_fb.param.trr_int = interval;
+ attr_p->attr.rtcp_fb.extra[0] = '\0';
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_rtcp_fb_remb
+ * Description: Sets the value of an rtcp-fb:...goog-remb attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * payload_type The value to set the payload type to for
+ * this attribute. Can be SDP_ALL_PAYLOADS.
+ * inst_num The attribute instance number to check.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_rtcp_fb_remb(sdp_t *sdp_p, uint16_t level, uint16_t payload_type,
+ uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp_fb goog-remb attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.rtcp_fb.payload_num = payload_type;
+ attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_REMB;
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_set_rtcp_fb_ccm
+ * Description: Sets the value of an rtcp-fb:...ccm attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * payload_type The value to set the payload type to for
+ * this attribute. Can be SDP_ALL_PAYLOADS.
+ * inst_num The attribute instance number to check.
+ * type The ccm type to indicate
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst,
+ sdp_rtcp_fb_ccm_type_e type)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s rtcp_fb ccm attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ attr_p->attr.rtcp_fb.payload_num = payload_type;
+ attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_CCM;
+ attr_p->attr.rtcp_fb.param.ccm = type;
+ attr_p->attr.rtcp_fb.extra[0] = '\0';
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_attr_get_extmap_uri
+ * Description: Returns a pointer to the value of the encoding name
+ * parameter specified for the given attribute. Value is
+ * returned as a const ptr and so cannot be modified by the
+ * application. If the given attribute is not defined, NULL
+ * will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: Codec value or SDP_CODEC_INVALID.
+ */
+const char *sdp_attr_get_extmap_uri(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s extmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (NULL);
+ } else {
+ return (attr_p->attr.extmap.uri);
+ }
+}
+
+/* Function: sdp_attr_get_extmap_id
+ * Description: Returns the id of the extmap specified for the given
+ * attribute. If the given attribute is not defined, 0xFFFF
+ * will be returned.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to check for the attribute.
+ * inst_num The attribute instance number to check.
+ * Returns: The id of the extmap attribute.
+ */
+uint16_t sdp_attr_get_extmap_id(sdp_t *sdp_p, uint16_t level,
+ uint16_t inst_num)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num);
+ if (attr_p == NULL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s extmap attribute, level %u instance %u "
+ "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return 0xFFFF;
+ } else {
+ return (attr_p->attr.extmap.id);
+ }
+}
+
+/* Function: sdp_attr_set_extmap
+ * Description: Sets the value of an rtcp-fb:...ccm attribute
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * level The level to set the attribute.
+ * id The id to set the attribute.
+ * uri The uri to set the attribute.
+ * inst The attribute instance number to check.
+ * Returns: SDP_SUCCESS Attribute param was set successfully.
+ * SDP_INVALID_PARAMETER Specified attribute is not defined.
+ */
+sdp_result_e
+sdp_attr_set_extmap(sdp_t *sdp_p, uint16_t level, uint16_t id, const char* uri, uint16_t inst)
+{
+ sdp_attr_t *attr_p;
+
+ attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst);
+ if (!attr_p) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s extmap attribute, level %u "
+ "instance %u not found.", sdp_p->debug_str, (unsigned)level,
+ (unsigned)inst);
+ }
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ attr_p->attr.extmap.id = id;
+ sstrncpy(attr_p->attr.extmap.uri, uri, SDP_MAX_STRING_LEN+1);
+ return (SDP_SUCCESS);
+}
+
+const char *sdp_attr_get_msid_identifier(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst)
+{
+ sdp_attr_t *attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_MSID, inst);
+ if (!attr_p) {
+ return NULL;
+ }
+ return attr_p->attr.msid.identifier;
+}
+
+const char *sdp_attr_get_msid_appdata(sdp_t *sdp_p, uint16_t level,
+ uint8_t cap_num, uint16_t inst)
+{
+ sdp_attr_t *attr_p = sdp_find_attr(sdp_p, level, cap_num,
+ SDP_ATTR_MSID, inst);
+ if (!attr_p) {
+ return NULL;
+ }
+ return attr_p->attr.msid.appdata;
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c
new file mode 100644
index 000000000..80f1eb52d
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.c
@@ -0,0 +1,403 @@
+/* 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/. */
+
+#include "sdp_base64.h"
+
+/*
+ * Local definitions for Base64 to Raw table entries.
+ */
+#define INVALID_CHAR 0xFF /* Character not in supported Base64 set */
+#define WHITE_SPACE 0xFE /* Space, tab, newline, etc character */
+#define PADDING 0xFD /* The character '=' */
+
+#define PAD_CHAR '=' /* The character '=' */
+
+/* Maximum length of a base64 encoded line */
+#define MAX_BASE64_LINE_LENGTH 76
+
+/*
+ * base64_result_table
+ * String table for translating base64 error codes into human
+ * understanable strings.
+ */
+char *base64_result_table[BASE64_RESULT_MAX] =
+{
+ "Base64 successful",
+ "Base64 Buffer Overrun",
+ "Base64 Bad Data",
+ "Base64 Bad Padding",
+ "Base64 Bad Block Size"
+};
+
+/*
+ * base64_to_raw_table
+ * Heart of the Base64 decoding algorithm. Lookup table to convert
+ * the Base64 characters into their specified representative values.
+ * Invalid characters are marked with 0xFF, white space characters
+ * are marked with 0xFE, and the special pading character is marked
+ * with 0xFD.
+ */
+unsigned char base64_to_raw_table[128] =
+{
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */
+ 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */
+ 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */
+ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, 52, 53, /* 40-49 */
+ 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, /* 50-59 */
+ 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, /* 60-69 */
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70-79 */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80-89 */
+ 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, /* 90-99 */
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
+ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* 120-127 */
+};
+
+unsigned char raw_to_base64_table[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */
+ '8', '9', '+', '/' /* 60-63 */
+};
+
+/*
+ * base64_encode_size_bytes
+ *
+ * DESCRIPTION
+ * Estimates the size of buffer required for holding the result of
+ * encoding data of size raw_size_bytes.
+ *
+ * PARAMETERS
+ * raw_size_bytes = Estimated size of the un-encoded data in bytes.
+ *
+ * RETURN VALUE
+ * The size of destination buffer to use for encoding in bytes.
+ */
+int base64_est_encode_size_bytes (int raw_size_bytes)
+{
+ int length;
+
+ /*
+ * Find the number of bytes needed to represent the data
+ * using a 4/3 expansion ratio. That result must be
+ * rounded to the next higher multiple of four to account
+ * for padding. Then add in a term to account for any '\n's
+ * added.
+ */
+ length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) +
+ raw_size_bytes / MAX_BASE64_LINE_LENGTH;
+
+ return length;
+}
+
+/*
+ * base64_decode_size_bytes
+ *
+ * DESCRIPTION
+ * Estimates the size of buffer required for holding the result of
+ * decoding data of size base64_size_bytes.
+ *
+ * PARAMETERS
+ * base64_size_bytes = Estimated size of the Base64 data in bytes.
+ *
+ * RETURN VALUE
+ * The size of destination buffer to use for decoding in bytes.
+ */
+int base64_est_decode_size_bytes (int base64_size_bytes)
+{
+ int length;
+
+ length = (base64_size_bytes * 3 + 3) / 4;
+ return length;
+}
+
+/*
+ * base64_encode
+ *
+ * DESCRIPTION
+ * Encode data pointed to by src into the buffer pointer to by dest
+ * using the Base64 algorithm.
+ *
+ * NOTE: No trailing '\n' character will be added.
+ *
+ * NOTE: As per specification, '\n' will be placed every 76 chars.
+ *
+ * PARAMETERS
+ * src = Pointer to the raw data to base64 encode.
+ * src_bytes = The number of bytes in the src buffer to encode.
+ * dest = Pointer to the destination buffer where the converted data
+ * will reside when complete.
+ * dest_bytes = Initially holds the size of the destination buffer
+ * but at completion holds the number of bytes converted.
+ *
+ * RETURN VALUE
+ * base64_success if the buffer was successfully converted, the
+ * appropriate error code otherwise.
+ *
+ * The dest parameter holds the converted data.
+ *
+ * The dest_bytes parameter holds the actual number of bytes converted.
+ */
+base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
+{
+ int i, j=0;
+ int line_count = 0;
+ unsigned char index; /* index into base64 lookup table */
+ int smax = src_bytes-2; /* only do full multiples of 3 */
+ int dmax = *dest_bytes; /* destination maximum */
+
+ *dest_bytes = 0;
+
+ /* Do full groups. Base64 must be done in blocks of 3 src bytes */
+ for (i=0; i<smax; i+=3) {
+ /* Check to see if newline should be injected */
+ if (line_count>=MAX_BASE64_LINE_LENGTH) {
+ if (j<dmax){
+ dest[j++] = '\n';
+ } else {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ line_count = 0;
+ }
+
+ line_count += 4;
+
+ if ((j+3) < dmax) {
+
+ /* Find mapping of upper 6 bits */
+ index = (src[i] >> 2) & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 2 bits of first word, high 4 bits of second word */
+ index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 4 bits of second word, high 2 bits of third word */
+ index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 6 bits of third word */
+ index = src[i+2] & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+ } else {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+
+ /* Check to see if any more work must be done */
+ if (i<src_bytes) {
+
+ /* Check to see if a newline should be output */
+ if (line_count>=MAX_BASE64_LINE_LENGTH) {
+ if (j<dmax){
+ dest[j++] = '\n';
+ } else {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ line_count = 0;
+ }
+
+ line_count += 4;
+
+ /* Must fill another quantum */
+ if (j+4>dmax) {
+ /* No room left in output buffer! */
+ return BASE64_BUFFER_OVERRUN;
+ }
+
+ /* Find mapping of upper 6 bits */
+ index = (src[i] >> 2) & 0x3F;
+ dest[j++] = raw_to_base64_table[index];
+
+ /* check for another stragler */
+ if ((i+1)<src_bytes) {
+ /* bottom 2 bits of first word, high 4 bits of second word */
+ index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
+ dest[j++] = raw_to_base64_table[index];
+
+ /* bottom 4 bits of second word */
+ index = (src[i+1] << 2) & 0x3C;
+ dest[j++] = raw_to_base64_table[index];
+ dest[j++] = PAD_CHAR;
+ } else {
+ /* bottom 2 bits of first word */
+ index = (src[i] << 4) & 0x30;
+ dest[j++] = raw_to_base64_table[index];
+ dest[j++] = PAD_CHAR;
+ dest[j++] = PAD_CHAR;
+ }
+ }
+
+ *dest_bytes = j;
+
+ return BASE64_SUCCESS;
+}
+
+unsigned char base64_decode_get_raw(unsigned char index)
+{
+ /* only have 128 values, MSB must not be set! */
+ if (index >= 128) {
+ return INVALID_CHAR;
+ }
+ return base64_to_raw_table[index];
+}
+
+/*
+ * base64_decode
+ *
+ * DESCRIPTION
+ * Decode data pointed to by src into the buffer pointer to by dest
+ * using the Base64 algorithm.
+ *
+ * PARAMETERS
+ * src = Pointer to the Base64 data to decode.
+ * src_bytes = The number of bytes in the src buffer to decode.
+ * dest = Pointer to the destination buffer where the converted data
+ * will reside when complete.
+ * dest_bytes = Initially holds the size of the destination buffer
+ * but at completion holds the number of bytes converted.
+ *
+ * RETURN VALUE
+ * base64_success if the buffer was successfully converted, the
+ * appropriate error code otherwise.
+ *
+ * The dest parameter holds the converted data.
+ *
+ * The dest_bytes parameter holds the actual number of bytes converted.
+ */
+base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
+{
+ int i, j = 0;
+ int sindex = 0; /* Current NON-whitespace source
+ * index */
+ int pad_count=0; /* Number of padding characters
+ * encountered */
+ int dest_size_bytes = *dest_bytes; /* Save size of destination buffer */
+ unsigned char cindex; /* The current Base64 character to
+ * process */
+ unsigned char val; /* The value of the current Base64
+ * character */
+
+ *dest_bytes = 0;
+
+ for (i=0; i<src_bytes; i++) {
+ cindex = src[i];
+
+ val = base64_decode_get_raw(cindex);
+ if (val == INVALID_CHAR) {
+ /* Invalid base64 character */
+ return BASE64_BAD_DATA;
+ }
+
+ if (val == WHITE_SPACE) {
+ /* Ignore white space */
+ continue;
+ }
+
+ if (val == PADDING) {
+ /* we must be at the end-finish up */
+ pad_count++;
+ if (++i<src_bytes) {
+ /* can have up to 2 pad chars */
+ if (base64_decode_get_raw(src[i]) != PADDING) {
+ return BASE64_BAD_PADDING;
+ }
+
+ if (++i<src_bytes) {
+ /* should not have any more padding! */
+ return BASE64_BAD_PADDING;
+ }
+
+ pad_count++;
+ }
+
+ /* DONE! */
+ break;
+ }
+
+ /* Determine which portion of the 3 bytes this data will fill */
+ switch (sindex & 0x3) {
+ case 0:
+ /* Fill upper 6 bits */
+ if (j<dest_size_bytes) {
+ dest[j] = val << 2;
+ } else {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ break;
+ case 1:
+ /* Fill Bottom 2 bits */
+ dest[j++] |= val >> 4;
+
+ if (j<dest_size_bytes) {
+ /* Fill Top 4 bits */
+ dest[j] = (val << 4) & 0xF0;
+ } else {
+ /*
+ * Check to see if there is any more data present.
+ * Next base64 character MUST be a pad character and
+ * the rest of this data MUST be zero.
+ *
+ * If this is not the end of data then a buffer overrun
+ * has occurred
+ */
+ if ((val & 0x0F) ||
+ (i+1>=src_bytes) ||
+ (base64_decode_get_raw(src[i+1]) != PADDING)) {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+ break;
+ case 2:
+ /* Fill Bottom 4 bits */
+ dest[j++] |= val >> 2;
+
+ if (j<dest_size_bytes) {
+ /* Fill Top 2 bits */
+ dest[j] = (val << 6) & 0xC0;
+ } else {
+ /*
+ * Check to see if there is any more data present.
+ * Next base64 character MUST be a pad character and
+ * the rest of this data MUST be zero.
+ *
+ * If this is not the end of data then a buffer overrun
+ * has occurred
+ */
+ if ((val & 0x03) ||
+ (i+1>=src_bytes) ||
+ (base64_decode_get_raw(src[i+1]) != PADDING)) {
+ return BASE64_BUFFER_OVERRUN;
+ }
+ }
+ break;
+ case 3:
+ /*
+ * No need to check for overrun here since the
+ * previous case was already checked. If another
+ * group is present then case 0 will check again.
+ */
+
+ /* Fill Bottom 6 bits */
+ dest[j++] |= val;
+ break;
+ }
+ sindex++;
+ }
+
+ /* Check length for multiple of 3 bytes */
+ if (((j + pad_count)% 3) != 0) {
+ return BASE64_BAD_BLOCK_SIZE;
+ }
+
+ /* Save off the number of bytes converted */
+ *dest_bytes = j;
+
+ return BASE64_SUCCESS;
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.h b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.h
new file mode 100644
index 000000000..e264245b7
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_base64.h
@@ -0,0 +1,42 @@
+/* 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 _SDP_BASE64_H_
+#define _SDP_BASE64_H_
+
+/*
+ * base64_result_t
+ * Enumeration of the result codes for Base64 conversion.
+ */
+typedef enum base64_result_t_ {
+ BASE64_INVALID=-1,
+ BASE64_SUCCESS=0,
+ BASE64_BUFFER_OVERRUN,
+ BASE64_BAD_DATA,
+ BASE64_BAD_PADDING,
+ BASE64_BAD_BLOCK_SIZE,
+ BASE64_RESULT_MAX
+} base64_result_t;
+
+#define MAX_BASE64_STRING_LEN 60
+
+/* Result code string table */
+extern char *base64_result_table[];
+
+/*
+ * BASE64_RESULT_TO_STRING
+ * Macro to convert a Base64 result code into a human readable string.
+ */
+#define BASE64_RESULT_TO_STRING(_result) (((_result)>=0 && (_result)<BASE64_RESULT_MAX)?(base64_result_table[_result]):("UNKNOWN Result Code"))
+
+/* Prototypes */
+
+int base64_est_encode_size_bytes(int raw_size_bytes);
+int base64_est_decode_size_bytes(int base64_size_bytes);
+
+base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes);
+
+base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes);
+
+#endif /* _SDP_BASE64_H_ */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_config.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_config.c
new file mode 100644
index 000000000..74ccf6b32
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_config.c
@@ -0,0 +1,241 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+static const char* logTag = "sdp_config";
+
+/* Function: void *sdp_init_config()
+ * Description: Initialize SDP configuration structure with the
+ * following defaults:
+ * All debug levels turned OFF.
+ * All token lines required per RFC2327.
+ * No media types supported.
+ * No network types supported.
+ * No address types supported.
+ * No transport types supported.
+ * Parameters: None.
+ * Returns: A handle for the configuration as a void ptr.
+ */
+sdp_conf_options_t *sdp_init_config ()
+{
+ int i;
+ sdp_conf_options_t *conf_p;
+
+ conf_p = SDP_MALLOC(sizeof(sdp_conf_options_t));
+
+ if (!conf_p) {
+ CSFLogError(logTag, "SDP: could not allocate configuration object.");
+ return NULL;
+ }
+
+ /* Set default debug flags. */
+ conf_p->debug_flag[SDP_DEBUG_TRACE] = FALSE;
+ conf_p->debug_flag[SDP_DEBUG_WARNINGS] = FALSE;
+ conf_p->debug_flag[SDP_DEBUG_ERRORS] = FALSE;
+
+ /* Set required lines flags. Note: Only need to set those that */
+ /* are questionable. Most lines aren't required by default. */
+ conf_p->version_reqd = TRUE;
+ conf_p->owner_reqd = TRUE;
+ conf_p->session_name_reqd = TRUE;
+ conf_p->timespec_reqd = TRUE;
+
+ /* No media types supported by default. */
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ conf_p->media_supported[i] = FALSE;
+ }
+
+ /* No network types supported by default. */
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ conf_p->nettype_supported[i] = FALSE;
+ }
+
+ /* No address types supported by default. */
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ conf_p->addrtype_supported[i] = FALSE;
+ }
+
+ /* No transport types supported by default. */
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ conf_p->transport_supported[i] = FALSE;
+ }
+
+ /* No choose parameters allowed by default. */
+ for (i=0; i < SDP_MAX_CHOOSE_PARAMS; i++) {
+ conf_p->allow_choose[i] = FALSE;
+ }
+
+ /* Initialize statistics counts */
+ conf_p->num_parses = 0;
+ conf_p->num_builds = 0;
+ conf_p->num_not_sdp_desc = 0;
+ conf_p->num_invalid_token_order = 0;
+ conf_p->num_invalid_param = 0;
+ conf_p->num_no_resource = 0;
+
+ /* Parse error handler stuff */
+ conf_p->error_handler = NULL;
+ conf_p->error_handler_context = NULL;
+
+ CSFLogInfo(logTag, "SDP: Initialized config pointer: %p", conf_p);
+
+ return (conf_p);
+}
+
+void sdp_free_config(sdp_conf_options_t* conf_p) {
+ if (conf_p) {
+ SDP_FREE(conf_p);
+ }
+}
+
+/* Function: void sdp_appl_debug(sdp_conf_options_t *conf_p, sdp_debug_e debug_type,
+ * tinybool my_bool);
+ * Description: Define the default type of debug for the application.
+ * Valid debug types are ERRORS, WARNINGS, and TRACE. Each
+ * debug type can be turned on/off individually. The
+ * default debug level can be redefined at any time.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * debug_type Specifies the debug type being enabled/disabled.
+ * debug_flag Defines whether the debug should be enabled or not.
+ * Returns: Nothing.
+ */
+void sdp_appl_debug (sdp_conf_options_t *conf_p, sdp_debug_e debug_type,
+ tinybool debug_flag)
+{
+ if (debug_type < SDP_MAX_DEBUG_TYPES) {
+ conf_p->debug_flag[debug_type] = debug_flag;
+ }
+}
+
+
+/* Functions: void sdp_require_version
+ * void sdp_require_owner
+ * void sdp_require_session_name
+ * void sdp_require_timespec
+ * Description: These functions allow the application to not require several
+ * of the tokens that are specifically required by RFC 2327.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * version_required TRUE or FALSE whether the token should
+ * be required.
+ * Returns: Nothing.
+ */
+void sdp_require_version (sdp_conf_options_t *conf_p, tinybool version_required)
+{
+ conf_p->version_reqd = version_required;
+}
+
+void sdp_require_owner (sdp_conf_options_t *conf_p, tinybool owner_required)
+{
+ conf_p->owner_reqd = owner_required;
+}
+
+void sdp_require_session_name (sdp_conf_options_t *conf_p, tinybool sess_name_required)
+{
+ conf_p->session_name_reqd = sess_name_required;
+}
+
+void sdp_require_timespec (sdp_conf_options_t *conf_p, tinybool timespec_required)
+{
+ conf_p->timespec_reqd = timespec_required;
+}
+
+
+/* Function: sdp_media_supported
+ * Description: These functions allow the application to specify which
+ * media types it supports. The application must set any/all
+ * as required. No media types are supported by default.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * nettype The network type for which support is being set.
+ * media_supported TRUE or FALSE whether the support is provided.
+ * Returns: Nothing.
+ */
+void sdp_media_supported (sdp_conf_options_t *conf_p, sdp_media_e media_type,
+ tinybool media_supported)
+{
+ conf_p->media_supported[media_type] = media_supported;
+}
+
+
+/* Function: sdp_nettype_supported
+ * Description: This function allows the application to specify which
+ * network types it supports. The application must set
+ * any/all as required. No network types are supported by
+ * default.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * nettype The network type for which support is being set.
+ * nettype_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_nettype_supported (sdp_conf_options_t *conf_p, sdp_nettype_e nettype,
+ tinybool nettype_supported)
+{
+ conf_p->nettype_supported[nettype] = nettype_supported;
+}
+
+
+/* Function: sdp_addrtype_supported
+ * Description: This function allows the application to specify which
+ * address types it supports. The application must set
+ * any/all as required. No address types are supported by
+ * default.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * addrtype The address type for which support is being set.
+ * addrtype_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_addrtype_supported (sdp_conf_options_t *conf_p, sdp_addrtype_e addrtype,
+ tinybool addrtype_supported)
+{
+ conf_p->addrtype_supported[addrtype] = addrtype_supported;
+}
+
+
+/* Function: sdp_transport_supported
+ * Description: This function allows the application to specify which
+ * transport types it supports. The application must set
+ * any/all as required. No transport types are supported
+ * by default.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * transport The transport type for which support is being set.
+ * transport_supported TRUE or FALSE whether the support is
+ * provided.
+ * Returns: Nothing.
+ */
+void sdp_transport_supported (sdp_conf_options_t *conf_p, sdp_transport_e transport,
+ tinybool transport_supported)
+{
+ conf_p->transport_supported[transport] = transport_supported;
+}
+
+
+/* Function: sdp_allow_choose
+ * Description: These functions allow the CHOOSE parameter `$' to be
+ * specified in place of certain parameters.
+ * Parameters: conf_p The config handle returned by sdp_init_config.
+ * param The param that may or may not be CHOOSE.
+ * choose_allowed TRUE or FALSE whether the CHOOSE parameter
+ * should be allowed.
+ * Returns: Nothing.
+ */
+void sdp_allow_choose (sdp_conf_options_t *conf_p, sdp_choose_param_e param, tinybool choose_allowed)
+{
+ if (param < SDP_MAX_CHOOSE_PARAMS) {
+ conf_p->allow_choose[param] = choose_allowed;
+ }
+}
+
+void sdp_config_set_error_handler(sdp_conf_options_t *conf_p,
+ sdp_parse_error_handler handler,
+ void *context)
+{
+ conf_p->error_handler = handler;
+ conf_p->error_handler_context = context;
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c
new file mode 100644
index 000000000..da66c1c07
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_main.c
@@ -0,0 +1,1342 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+static const char* logTag = "sdp_main";
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_tokenarray_t sdp_token[SDP_MAX_TOKENS] =
+{
+ {"v=", sdp_parse_version, sdp_build_version },
+ {"o=", sdp_parse_owner, sdp_build_owner },
+ {"s=", sdp_parse_sessname, sdp_build_sessname },
+ {"i=", sdp_parse_sessinfo, sdp_build_sessinfo },
+ {"u=", sdp_parse_uri, sdp_build_uri },
+ {"e=", sdp_parse_email, sdp_build_email },
+ {"p=", sdp_parse_phonenum, sdp_build_phonenum },
+ {"c=", sdp_parse_connection, sdp_build_connection },
+ {"b=", sdp_parse_bandwidth, sdp_build_bandwidth },
+ {"t=", sdp_parse_timespec, sdp_build_timespec },
+ {"r=", sdp_parse_repeat_time, sdp_build_repeat_time },
+ {"z=", sdp_parse_timezone_adj, sdp_build_timezone_adj },
+ {"k=", sdp_parse_encryption, sdp_build_encryption },
+ {"a=", sdp_parse_attribute, sdp_build_attribute },
+ {"m=", sdp_parse_media, sdp_build_media }
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] =
+{
+ {"bearer", sizeof("bearer"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"called", sizeof("called"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"connection_type", sizeof("connection_type"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"dialed", sizeof("dialed"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"dialing", sizeof("dialing"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"direction", sizeof("direction"),
+ sdp_parse_attr_comediadir, sdp_build_attr_comediadir },
+ {"eecid", sizeof("eecid"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"fmtp", sizeof("fmtp"),
+ sdp_parse_attr_fmtp, sdp_build_attr_fmtp },
+ {"sctpmap", sizeof("sctpmap"),
+ sdp_parse_attr_sctpmap, sdp_build_attr_sctpmap },
+ {"framing", sizeof("framing"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"inactive", sizeof("inactive"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"ptime", sizeof("ptime"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"qos", sizeof("qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"curr", sizeof("curr"),
+ sdp_parse_attr_curr, sdp_build_attr_curr },
+ {"des", sizeof("des"),
+ sdp_parse_attr_des, sdp_build_attr_des},
+ {"conf", sizeof("conf"),
+ sdp_parse_attr_conf, sdp_build_attr_conf},
+ {"recvonly", sizeof("recvonly"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"rtpmap", sizeof("rtpmap"),
+ sdp_parse_attr_transport_map, sdp_build_attr_transport_map },
+ {"secure", sizeof("secure"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"sendonly", sizeof("sendonly"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"sendrecv", sizeof("sendrecv"),
+ sdp_parse_attr_direction, sdp_build_attr_direction },
+ {"subnet", sizeof("subnet"),
+ sdp_parse_attr_subnet, sdp_build_attr_subnet },
+ {"T38FaxVersion", sizeof("T38FaxVersion"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38MaxBitRate", sizeof("T38MaxBitRate"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxFillBitRemoval", sizeof("T38FaxFillBitRemoval"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxTranscodingMMR", sizeof("T38FaxTranscodingMMR"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxTranscodingJBIG", sizeof("T38FaxTranscodingJBIG"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"T38FaxRateManagement", sizeof("T38FaxRateManagement"),
+ sdp_parse_attr_t38_ratemgmt, sdp_build_attr_t38_ratemgmt },
+ {"T38FaxMaxBuffer", sizeof("T38FaxMaxBuffer"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxMaxDatagram", sizeof("T38FaxMaxDatagram"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"T38FaxUdpEC", sizeof("T38FaxUdpEC"),
+ sdp_parse_attr_t38_udpec, sdp_build_attr_t38_udpec },
+ {"X-cap", sizeof("X-cap"),
+ sdp_parse_attr_cap, sdp_build_attr_cap },
+ {"X-cpar", sizeof("X-cpar"),
+ sdp_parse_attr_cpar, sdp_build_attr_cpar },
+ {"X-pc-codec", sizeof("X-pc-codec"),
+ sdp_parse_attr_pc_codec, sdp_build_attr_pc_codec },
+ {"X-pc-qos", sizeof("X-pc-qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"X-qos", sizeof("X-qos"),
+ sdp_parse_attr_qos, sdp_build_attr_qos },
+ {"X-sqn", sizeof("X-sqn"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TMRGwXid", sizeof("TMRGwXid"),
+ sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool },
+ {"TC1PayloadBytes", sizeof("TC1PayloadBytes"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC1WindowSize", sizeof("TC1WindowSize"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC2PayloadBytes", sizeof("TC2PayloadBytes"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"TC2WindowSize", sizeof("TC2WindowSize"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"rtcp", sizeof("rtcp"),
+ sdp_parse_attr_rtcp, sdp_build_attr_rtcp },
+ {"rtr", sizeof("rtr"),
+ sdp_parse_attr_rtr, sdp_build_attr_rtr},
+ {"silenceSupp", sizeof("silenceSupp"),
+ sdp_parse_attr_silencesupp, sdp_build_attr_silencesupp },
+ {"X-crypto", sizeof("X-crypto"),
+ sdp_parse_attr_srtpcontext, sdp_build_attr_srtpcontext },
+ {"mptime", sizeof("mptime"),
+ sdp_parse_attr_mptime, sdp_build_attr_mptime },
+ {"X-sidin", sizeof("X-sidin"),
+ sdp_parse_attr_x_sidin, sdp_build_attr_x_sidin },
+ {"X-sidout", sizeof("X-sidout"),
+ sdp_parse_attr_x_sidout, sdp_build_attr_x_sidout },
+ {"X-confid", sizeof("X-confid"),
+ sdp_parse_attr_x_confid, sdp_build_attr_x_confid },
+ {"group", sizeof("group"),
+ sdp_parse_attr_group, sdp_build_attr_group },
+ {"mid", sizeof("mid"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"source-filter", sizeof("source-filter"),
+ sdp_parse_attr_source_filter, sdp_build_source_filter},
+ {"rtcp-unicast", sizeof("rtcp-unicast"),
+ sdp_parse_attr_rtcp_unicast, sdp_build_attr_rtcp_unicast},
+ {"maxprate", sizeof("maxprate"),
+ sdp_parse_attr_maxprate, sdp_build_attr_simple_string},
+ {"sqn", sizeof("sqn"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"cdsc", sizeof("cdsc"),
+ sdp_parse_attr_cap, sdp_build_attr_cap },
+ {"cpar", sizeof("cpar"),
+ sdp_parse_attr_cpar, sdp_build_attr_cpar },
+ {"sprtmap", sizeof("sprtmap"),
+ sdp_parse_attr_transport_map, sdp_build_attr_transport_map },
+ {"crypto", sizeof("crypto"),
+ sdp_parse_attr_sdescriptions, sdp_build_attr_sdescriptions },
+ {"label", sizeof("label"),
+ sdp_parse_attr_simple_string, sdp_build_attr_simple_string },
+ {"framerate", sizeof("framerate"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 },
+ {"candidate", sizeof("candidate"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
+ {"ice-ufrag", sizeof("ice-ufrag"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr },
+ {"ice-pwd", sizeof("ice-pwd"),
+ sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr},
+ {"ice-lite", sizeof("ice-lite"),
+ sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
+ {"rtcp-mux", sizeof("rtcp-mux"),
+ sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
+ {"fingerprint", sizeof("fingerprint"),
+ sdp_parse_attr_complete_line, sdp_build_attr_simple_string},
+ {"maxptime", sizeof("maxptime"),
+ sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32},
+ {"rtcp-fb", sizeof("rtcp-fb"),
+ sdp_parse_attr_rtcp_fb, sdp_build_attr_rtcp_fb},
+ {"setup", sizeof("setup"),
+ sdp_parse_attr_setup, sdp_build_attr_setup},
+ {"connection", sizeof("connection"),
+ sdp_parse_attr_connection, sdp_build_attr_connection},
+ {"extmap", sizeof("extmap"),
+ sdp_parse_attr_extmap, sdp_build_attr_extmap},
+ {"identity", sizeof("identity"),
+ sdp_parse_attr_long_line, sdp_build_attr_long_line},
+ {"msid", sizeof("msid"),
+ sdp_parse_attr_msid, sdp_build_attr_msid},
+ {"msid-semantic", sizeof("msid-semantic"),
+ sdp_parse_attr_msid_semantic, sdp_build_attr_msid_semantic},
+ {"bundle-only", sizeof("bundle-only"),
+ sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
+ {"end-of-candidates", sizeof("end-of-candidates"),
+ sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag},
+ {"ice-options", sizeof("ice-options"),
+ sdp_parse_attr_complete_line, sdp_build_attr_simple_string},
+ {"ssrc", sizeof("ssrc"),
+ sdp_parse_attr_ssrc, sdp_build_attr_ssrc},
+ {"imageattr", sizeof("imageattr"),
+ sdp_parse_attr_complete_line, sdp_build_attr_simple_string},
+ {"simulcast", sizeof("simulcast"),
+ sdp_parse_attr_complete_line, sdp_build_attr_simple_string},
+ {"rid", sizeof("rid"),
+ sdp_parse_attr_complete_line, sdp_build_attr_simple_string},
+ {"dtls-message", sizeof("dtls-message"),
+ sdp_parse_attr_long_line, sdp_build_attr_long_line},
+};
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_media[SDP_MAX_MEDIA_TYPES] =
+{
+ {"audio", sizeof("audio")},
+ {"video", sizeof("video")},
+ {"application", sizeof("application")},
+ {"data", sizeof("data")},
+ {"control", sizeof("control")},
+ {"nas/radius", sizeof("nas/radius")},
+ {"nas/tacacs", sizeof("nas/tacacs")},
+ {"nas/diameter", sizeof("nas/diameter")},
+ {"nas/l2tp", sizeof("nas/l2tp")},
+ {"nas/login", sizeof("nas/login")},
+ {"nas/none", sizeof("nas/none")},
+ {"image", sizeof("image")},
+ {"text", sizeof("text")}
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_nettype[SDP_MAX_NETWORK_TYPES] =
+{
+ {"IN", sizeof("IN")},
+ {"ATM", sizeof("ATM")},
+ {"FR", sizeof("FR")},
+ {"LOCAL", sizeof("LOCAL")}
+};
+
+
+/* Note: These *must* be in the same order as the enum types. */
+const sdp_namearray_t sdp_addrtype[SDP_MAX_ADDR_TYPES] =
+{
+ {"IP4", sizeof("IP4")},
+ {"IP6", sizeof("IP6")},
+ {"NSAP", sizeof("NSAP")},
+ {"EPN", sizeof("EPN")},
+ {"E164", sizeof("E164")},
+ {"GWID", sizeof("GWID")}
+};
+
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_transport[SDP_MAX_TRANSPORT_TYPES] =
+{
+ {"RTP/AVP", sizeof("RTP/AVP")},
+ {"udp", sizeof("udp")},
+ {"udptl", sizeof("udptl")},
+ {"ces10", sizeof("ces10")},
+ {"LOCAL", sizeof("LOCAL")},
+ {"AAL2/ITU", sizeof("AAL2/ITU")},
+ {"AAL2/ATMF", sizeof("AAL2/ATMF")},
+ {"AAL2/custom", sizeof("AAL2/custom")},
+ {"AAL1/AVP", sizeof("AAL1/AVP")},
+ {"udpsprt", sizeof("udpsprt")},
+ {"RTP/SAVP", sizeof("RTP/SAVP")},
+ {"tcp", sizeof("tcp")},
+ {"RTP/SAVPF", sizeof("RTP/SAVPF")},
+ {"DTLS/SCTP", sizeof("DTLS/SCTP")},
+ {"RTP/AVPF", sizeof("RTP/AVPF")},
+ {"UDP/TLS/RTP/SAVP", sizeof("UDP/TLS/RTP/SAVP")},
+ {"UDP/TLS/RTP/SAVPF", sizeof("UDP/TLS/RTP/SAVPF")},
+ {"TCP/TLS/RTP/SAVP", sizeof("TCP/TLS/RTP/SAVP")},
+ {"TCP/TLS/RTP/SAVPF", sizeof("TCP/TLS/RTP/SAVPF")},
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_encrypt[SDP_MAX_ENCRYPT_TYPES] =
+{
+ {"clear", sizeof("clear")},
+ {"base64", sizeof("base64")},
+ {"uri", sizeof("uri")},
+ {"prompt", sizeof("prompt")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_payload[SDP_MAX_STRING_PAYLOAD_TYPES] =
+{
+ {"t38", sizeof("t38")},
+ {"X-tmr", sizeof("X-tmr")},
+ {"T120", sizeof("T120")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_t38_rate[SDP_T38_MAX_RATES] =
+{
+ {"localTCF", sizeof("localTCF")},
+ {"transferredTCF", sizeof("transferredTCF")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_t38_udpec[SDP_T38_MAX_UDPEC] =
+{
+ {"t38UDPRedundancy", sizeof("t38UDPRedundancy")},
+ {"t38UDPFEC", sizeof("t38UDPFEC")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_strength[SDP_MAX_QOS_STRENGTH] =
+{
+ {"optional", sizeof("optional")},
+ {"mandatory", sizeof("mandatory")},
+ {"success", sizeof("success")},
+ {"failure", sizeof("failure")},
+ {"none", sizeof("none")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_status_type[SDP_MAX_QOS_STATUS_TYPES] =
+{
+ {"local", sizeof("local")},
+ {"remote", sizeof("remote")},
+ {"e2e", sizeof("e2e")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_curr_type[SDP_MAX_CURR_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_des_type[SDP_MAX_DES_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_conf_type[SDP_MAX_CONF_TYPES] =
+{
+ {"qos", sizeof("qos")},
+ {"unknown", sizeof("unknown")}
+};
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_qos_direction[SDP_MAX_QOS_DIR] =
+{
+ {"send", sizeof("send")},
+ {"recv", sizeof("recv")},
+ {"sendrecv", sizeof("sendrecv")},
+ {"none", sizeof("none")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_silencesupp_pref[SDP_MAX_SILENCESUPP_PREF] = {
+ {"standard", sizeof("standard")},
+ {"custom", sizeof("custom")},
+ {"-", sizeof("-")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_silencesupp_siduse[SDP_MAX_SILENCESUPP_SIDUSE] = {
+ {"No SID", sizeof("No SID")},
+ {"Fixed Noise", sizeof("Fixed Noise")},
+ {"Sampled Noise", sizeof("Sampled Noise")},
+ {"-", sizeof("-")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_mediadir_role[SDP_MAX_MEDIADIR_ROLES] =
+{
+ {"passive", sizeof("passive")},
+ {"active", sizeof("active")},
+ {"both", sizeof("both")},
+ {"reuse", sizeof("reuse")},
+ {"unknown", sizeof("unknown")}
+};
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_fmtp_codec_param[SDP_MAX_FMTP_PARAM] =
+{
+ {"annexa", sizeof("annexa")}, /* 0 */
+ {"annexb", sizeof("annexb")}, /* 1 */
+ {"bitrate", sizeof("bitrate")}, /* 2 */
+ {"QCIF", sizeof("QCIF")}, /* 3 */
+ {"CIF", sizeof("CIF")}, /* 4 */
+ {"MAXBR", sizeof("MAXBR")}, /* 5 */
+ {"SQCIF", sizeof("SQCIF")}, /* 6 */
+ {"CIF4", sizeof("CIF4")}, /* 7 */
+ {"CIF16", sizeof("CIF16")}, /* 8 */
+ {"CUSTOM", sizeof("CUSTOM")}, /* 9 */
+ {"PAR", sizeof("PAR")}, /* 10 */
+ {"CPCF", sizeof("CPCF")}, /* 11 */
+ {"BPP", sizeof("BPP")}, /* 12 */
+ {"HRD", sizeof("HRD")}, /* 13 */
+ {"PROFILE", sizeof("PROFILE")}, /* 14 */
+ {"LEVEL", sizeof("LEVEL")}, /* 15 */
+ {"INTERLACE", sizeof("INTERLACE")}, /* 16 */
+
+ /* H.264 related */
+ {"profile-level-id", sizeof("profile-level-id")}, /* 17 */
+ {"sprop-parameter-sets", sizeof("sprop-parameter-sets")}, /* 18 */
+ {"packetization-mode", sizeof("packetization-mode")}, /* 19 */
+ {"sprop-interleaving-depth", sizeof("sprop-interleaving-depth")}, /* 20 */
+ {"sprop-deint-buf-req", sizeof("sprop-deint-buf-req")}, /* 21 */
+ {"sprop-max-don-diff", sizeof("sprop-max-don-diff")}, /* 22 */
+ {"sprop-init-buf-time", sizeof("sprop-init-buf-time")}, /* 23 */
+
+ {"max-mbps", sizeof("max-mbps")}, /* 24 */
+ {"max-fs", sizeof("max-fs")}, /* 25 */
+ {"max-cpb", sizeof("max-cpb")}, /* 26 */
+ {"max-dpb", sizeof("max-dpb")}, /* 27 */
+ {"max-br", sizeof("max-br")}, /* 28 */
+ {"redundant-pic-cap", sizeof("redundant-pic-cap")}, /* 29 */
+ {"deint-buf-cap", sizeof("deint-buf-cap")}, /* 30 */
+ {"max-rcmd-nalu-size", sizeof("max-rcmd_nali-size")}, /* 31 */
+ {"parameter-add", sizeof("parameter-add")}, /* 32 */
+
+ /* Annexes - require special handling */
+ {"D", sizeof("D")}, /* 33 */
+ {"F", sizeof("F")}, /* 34 */
+ {"I", sizeof("I")}, /* 35 */
+ {"J", sizeof("J")}, /* 36 */
+ {"T", sizeof("T")}, /* 37 */
+ {"K", sizeof("K")}, /* 38 */
+ {"N", sizeof("N")}, /* 39 */
+ {"P", sizeof("P")}, /* 40 */
+
+ {"mode", sizeof("mode")}, /* 41 */
+ {"level-asymmetry-allowed", sizeof("level-asymmetry-allowed")}, /* 42 */
+ {"maxaveragebitrate", sizeof("maxaveragebitrate")}, /* 43 */
+ {"usedtx", sizeof("usedtx")}, /* 44 */
+ {"stereo", sizeof("stereo")}, /* 45 */
+ {"useinbandfec", sizeof("useinbandfec")}, /* 46 */
+ {"maxcodedaudiobandwidth", sizeof("maxcodedaudiobandwidth")}, /* 47 */
+ {"cbr", sizeof("cbr")}, /* 48 */
+ {"max-fr", sizeof("max-fr")}, /* 49 */
+ {"maxplaybackrate", sizeof("maxplaybackrate")} /* 50 */
+} ;
+
+/* Note: These *must* be in the same order as the enum type. */
+const sdp_namearray_t sdp_fmtp_codec_param_val[SDP_MAX_FMTP_PARAM_VAL] =
+{
+ {"yes", sizeof("yes")},
+ {"no", sizeof("no")}
+};
+
+const sdp_namearray_t sdp_bw_modifier_val[SDP_MAX_BW_MODIFIER_VAL] =
+{
+ {"AS", sizeof("AS")},
+ {"CT", sizeof("CT")},
+ {"TIAS", sizeof("TIAS")}
+};
+
+const sdp_namearray_t sdp_group_attr_val[SDP_MAX_GROUP_ATTR_VAL] =
+{
+ {"FID", sizeof("FID")},
+ {"LS", sizeof("LS")},
+ {"ANAT", sizeof("ANAT")},
+ {"BUNDLE", sizeof("BUNDLE")}
+};
+
+const sdp_namearray_t sdp_srtp_context_crypto_suite[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
+{
+ {"UNKNOWN_CRYPTO_SUITE", sizeof("UNKNOWN_CRYPTO_SUITE")},
+ {"AES_CM_128_HMAC_SHA1_32", sizeof("AES_CM_128_HMAC_SHA1_32")},
+ {"AES_CM_128_HMAC_SHA1_80", sizeof("AES_CM_128_HMAC_SHA1_80")},
+ {"F8_128_HMAC_SHA1_80", sizeof("F8_128_HMAC_SHA1_80")}
+};
+
+/* Maintain the same order as defined in typedef sdp_src_filter_mode_e */
+const sdp_namearray_t sdp_src_filter_mode_val[SDP_MAX_FILTER_MODE] =
+{
+ {"incl", sizeof("incl")},
+ {"excl", sizeof("excl")}
+};
+
+/* Maintain the same order as defined in typdef sdp_rtcp_unicast_mode_e */
+const sdp_namearray_t sdp_rtcp_unicast_mode_val[SDP_RTCP_MAX_UNICAST_MODE] =
+{
+ {"reflection", sizeof("reflection")},
+ {"rsi", sizeof("rsi")}
+};
+
+#define SDP_NAME(x) {x, sizeof(x)}
+/* Maintain the same order as defined in typdef sdp_rtcp_fb_type_e */
+const sdp_namearray_t sdp_rtcp_fb_type_val[SDP_MAX_RTCP_FB] =
+{
+ SDP_NAME("ack"),
+ SDP_NAME("ccm"),
+ SDP_NAME("nack"),
+ SDP_NAME("trr-int"),
+ SDP_NAME("goog-remb")
+};
+
+/* Maintain the same order as defined in typdef sdp_rtcp_fb_nack_type_e */
+const sdp_namearray_t sdp_rtcp_fb_nack_type_val[SDP_MAX_RTCP_FB_NACK] =
+{
+ SDP_NAME(""),
+ SDP_NAME("sli"),
+ SDP_NAME("pli"),
+ SDP_NAME("rpsi"),
+ SDP_NAME("app"),
+ SDP_NAME("rai"),
+ SDP_NAME("tllei"),
+ SDP_NAME("pslei"),
+ SDP_NAME("ecn")
+};
+
+/* Maintain the same order as defined in typdef sdp_rtcp_fb_ack_type_e */
+const sdp_namearray_t sdp_rtcp_fb_ack_type_val[SDP_MAX_RTCP_FB_ACK] =
+{
+ SDP_NAME("rpsi"),
+ SDP_NAME("app")
+};
+
+/* Maintain the same order as defined in typdef sdp_rtcp_fb_ccm_type_e */
+const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[SDP_MAX_RTCP_FB_CCM] =
+{
+ SDP_NAME("fir"),
+ SDP_NAME("tmmbr"),
+ SDP_NAME("tstr"),
+ SDP_NAME("vbcm")
+};
+
+/* Maintain the same order as defined in typedef sdp_setup_type_e */
+const sdp_namearray_t sdp_setup_type_val[SDP_MAX_SETUP] =
+{
+ SDP_NAME("active"),
+ SDP_NAME("passive"),
+ SDP_NAME("actpass"),
+ SDP_NAME("holdconn")
+};
+
+/* Maintain the same order as defined in typedef sdp_connection_type_e */
+const sdp_namearray_t sdp_connection_type_val[SDP_MAX_CONNECTION] =
+{
+ SDP_NAME("new"),
+ SDP_NAME("existing")
+};
+
+/* Maintain same order as defined in typedef sdp_srtp_crypto_suite_t */
+const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] =
+{
+ {SDP_SRTP_UNKNOWN_CRYPTO_SUITE, UNKNOWN_CRYPTO_SUITE, 0, 0},
+ {SDP_SRTP_AES_CM_128_HMAC_SHA1_32, AES_CM_128_HMAC_SHA1_32,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES},
+ {SDP_SRTP_AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_80,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES,
+ SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES},
+ {SDP_SRTP_F8_128_HMAC_SHA1_80, F8_128_HMAC_SHA1_80,
+ SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES,
+ SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES}
+};
+
+const char* sdp_result_name[SDP_MAX_RC] =
+ {"SDP_SUCCESS",
+ "SDP_FAILURE",
+ "SDP_INVALID_SDP_PTR",
+ "SDP_NOT_SDP_DESCRIPTION",
+ "SDP_INVALID_TOKEN_ORDERING",
+ "SDP_INVALID_PARAMETER",
+ "SDP_INVALID_MEDIA_LEVEL",
+ "SDP_INVALID_CAPABILITY",
+ "SDP_NO_RESOURCE",
+ "SDP_UNRECOGNIZED_TOKEN",
+ "SDP_NULL_BUF_PTR",
+ "SDP_POTENTIAL_SDP_OVERFLOW",
+ "SDP_EMPTY_TOKEN"};
+
+const char *sdp_get_result_name ( sdp_result_e rc )
+{
+ if (rc >= SDP_MAX_RC) {
+ return ("Invalid SDP result code");
+ } else {
+ return (sdp_result_name[rc]);
+ }
+}
+
+const char *sdp_get_attr_name ( sdp_attr_e attr_type )
+{
+ if (attr_type >= SDP_MAX_ATTR_TYPES) {
+ return ("Invalid attribute type");
+ } else {
+ return (sdp_attr[attr_type].name);
+ }
+}
+
+const char *sdp_get_media_name ( sdp_media_e media_type )
+{
+ if (media_type == SDP_MEDIA_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (media_type >= SDP_MAX_MEDIA_TYPES) {
+ return ("Invalid media type");
+ } else {
+ return (sdp_media[media_type].name);
+ }
+}
+
+const char *sdp_get_network_name ( sdp_nettype_e network_type )
+{
+ if (network_type == SDP_NT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (network_type >= SDP_MAX_NETWORK_TYPES) {
+ return ("Invalid network type");
+ } else {
+ return (sdp_nettype[network_type].name);
+ }
+}
+
+const char *sdp_get_address_name ( sdp_addrtype_e addr_type )
+{
+ if (addr_type == SDP_AT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (addr_type >= SDP_MAX_ADDR_TYPES) {
+ if (addr_type == SDP_AT_FQDN) {
+ return ("*");
+ } else {
+ return ("Invalid address type");
+ }
+ } else {
+ return (sdp_addrtype[addr_type].name);
+ }
+}
+
+const char *sdp_get_transport_name ( sdp_transport_e transport_type )
+{
+ if (transport_type == SDP_TRANSPORT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (transport_type >= SDP_MAX_TRANSPORT_TYPES) {
+ return ("Invalid transport type");
+ } else {
+ return (sdp_transport[transport_type].name);
+ }
+}
+
+const char *sdp_get_encrypt_name ( sdp_encrypt_type_e encrypt_type )
+{
+ if (encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (encrypt_type >= SDP_MAX_ENCRYPT_TYPES) {
+ return ("Invalid encryption type");
+ } else {
+ return (sdp_encrypt[encrypt_type].name);
+ }
+}
+
+const char *sdp_get_payload_name ( sdp_payload_e payload )
+{
+ if (payload == SDP_PAYLOAD_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (payload >= SDP_MAX_STRING_PAYLOAD_TYPES) {
+ return ("Invalid payload type");
+ } else {
+ return (sdp_payload[payload].name);
+ }
+}
+
+const char *sdp_get_t38_ratemgmt_name ( sdp_t38_ratemgmt_e rate )
+{
+ if (rate >= SDP_T38_MAX_RATES) {
+ return ("Invalid rate");
+ } else {
+ return (sdp_t38_rate[rate].name);
+ }
+}
+
+const char *sdp_get_t38_udpec_name ( sdp_t38_udpec_e udpec )
+{
+ if (udpec >= SDP_T38_MAX_UDPEC) {
+ return ("Invalid udpec");
+ } else {
+ return (sdp_t38_udpec[udpec].name);
+ }
+}
+
+const char *sdp_get_qos_strength_name ( sdp_qos_strength_e strength )
+{
+ if (strength >= SDP_MAX_QOS_STRENGTH) {
+ return ("Invalid qos strength");
+ } else {
+ return (sdp_qos_strength[strength].name);
+ }
+}
+
+const char *sdp_get_qos_direction_name ( sdp_qos_dir_e direction )
+{
+ if (direction >= SDP_MAX_QOS_DIR) {
+ return ("Invalid qos direction");
+ } else {
+ return (sdp_qos_direction[direction].name);
+ }
+}
+
+const char *sdp_get_qos_status_type_name ( sdp_qos_status_types_e status_type )
+{
+ if (status_type >= SDP_MAX_QOS_STATUS_TYPES) {
+ return ("Invalid qos status type");
+ } else {
+ return (sdp_qos_status_type[status_type].name);
+ }
+}
+
+const char *sdp_get_curr_type_name (sdp_curr_type_e curr_type )
+{
+ if (curr_type >= SDP_MAX_CURR_TYPES) {
+ return ("Invalid curr type");
+ } else {
+ return (sdp_curr_type[curr_type].name);
+ }
+}
+
+const char *sdp_get_des_type_name (sdp_des_type_e des_type )
+{
+ if (des_type >= SDP_MAX_DES_TYPES) {
+ return ("Invalid des type");
+ } else {
+ return (sdp_des_type[des_type].name);
+ }
+}
+
+const char *sdp_get_conf_type_name (sdp_conf_type_e conf_type )
+{
+ if (conf_type >= SDP_MAX_CONF_TYPES) {
+ return ("Invalid conf type");
+ } else {
+ return (sdp_conf_type[conf_type].name);
+ }
+}
+
+const char *sdp_get_silencesupp_pref_name (sdp_silencesupp_pref_e pref)
+{
+ if (pref >= SDP_MAX_SILENCESUPP_PREF) {
+ return ("Invalid silencesupp pref");
+ } else {
+ return (sdp_silencesupp_pref[pref].name);
+ }
+}
+
+const char *sdp_get_silencesupp_siduse_name (sdp_silencesupp_siduse_e siduse)
+{
+ if (siduse >= SDP_MAX_SILENCESUPP_SIDUSE) {
+ return ("Invalid silencesupp siduse");
+ } else {
+ return (sdp_silencesupp_siduse[siduse].name);
+ }
+}
+
+const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role)
+{
+ if (role >= SDP_MEDIADIR_ROLE_UNKNOWN) {
+ return ("Invalid media direction role");
+ } else {
+ return (sdp_mediadir_role[role].name);
+ }
+}
+
+
+const char *sdp_get_bw_modifier_name (sdp_bw_modifier_e bw_modifier_type)
+{
+ if (bw_modifier_type == SDP_BW_MODIFIER_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (bw_modifier_type < SDP_BW_MODIFIER_AS ||
+ bw_modifier_type >= SDP_MAX_BW_MODIFIER_VAL) {
+ return ("Invalid bw modifier type");
+ } else {
+ return (sdp_bw_modifier_val[bw_modifier_type].name);
+ }
+}
+
+const char *sdp_get_group_attr_name (sdp_group_attr_e group_attr_type)
+{
+ if (group_attr_type == SDP_GROUP_ATTR_UNSUPPORTED) {
+ return (SDP_UNSUPPORTED);
+ } else if (group_attr_type >= SDP_MAX_GROUP_ATTR_VAL) {
+ return ("Invalid a=group: attribute type");
+ } else {
+ return (sdp_group_attr_val[group_attr_type].name);
+ }
+}
+
+const char *sdp_get_src_filter_mode_name (sdp_src_filter_mode_e type)
+{
+ if (type >= SDP_MAX_FILTER_MODE) {
+ return ("Invalid source filter mode");
+ } else {
+ return (sdp_src_filter_mode_val[type].name);
+ }
+}
+
+const char *sdp_get_rtcp_unicast_mode_name (sdp_rtcp_unicast_mode_e type)
+{
+ if (type >= SDP_RTCP_MAX_UNICAST_MODE) {
+ return ("Invalid rtcp unicast mode");
+ } else {
+ return (sdp_rtcp_unicast_mode_val[type].name);
+ }
+}
+
+/* Function: sdp_init_description
+ * Description: Allocates a new SDP structure that can be used for either
+ * parsing or building an SDP description. This routine
+ * saves the config pointer passed in the SDP structure so
+ * SDP will know how to parse/build based on the options defined.
+ * An SDP structure must be allocated before parsing or building
+ * since the handle must be passed to these routines.
+ * Parameters: config_p The config handle returned by sdp_init_config
+ * Returns: A handle for a new SDP structure as a void ptr.
+*/
+sdp_t *sdp_init_description (sdp_conf_options_t *conf_p)
+{
+ int i;
+ sdp_t *sdp_p;
+
+ if (!conf_p) {
+ return (NULL);
+ }
+
+ sdp_p = (sdp_t *)SDP_MALLOC(sizeof(sdp_t));
+ if (sdp_p == NULL) {
+ return (NULL);
+ }
+
+ sdp_p->conf_p = conf_p;
+ sdp_p->version = SDP_CURRENT_VERSION;
+ sdp_p->owner_name[0] = '\0';
+ sdp_p->owner_sessid[0] = '\0';
+ sdp_p->owner_version[0] = '\0';
+ sdp_p->owner_network_type = SDP_NT_INVALID;
+ sdp_p->owner_addr_type = SDP_AT_INVALID;
+ sdp_p->owner_addr[0] = '\0';
+ sdp_p->sessname[0] = '\0';
+ sdp_p->sessinfo_found = FALSE;
+ sdp_p->uri_found = FALSE;
+
+ sdp_p->default_conn.nettype = SDP_NT_INVALID;
+ sdp_p->default_conn.addrtype = SDP_AT_INVALID;
+ sdp_p->default_conn.conn_addr[0] = '\0';
+ sdp_p->default_conn.is_multicast = FALSE;
+ sdp_p->default_conn.ttl = 0;
+ sdp_p->default_conn.num_of_addresses = 0;
+
+ sdp_p->bw.bw_data_count = 0;
+ sdp_p->bw.bw_data_list = NULL;
+
+ sdp_p->timespec_p = NULL;
+ sdp_p->sess_attrs_p = NULL;
+ sdp_p->mca_p = NULL;
+ sdp_p->mca_count = 0;
+
+ /* Set default debug flags from application config. */
+ for (i=0; i < SDP_MAX_DEBUG_TYPES; i++) {
+ sdp_p->debug_flag[i] = conf_p->debug_flag[i];
+ }
+
+ return (sdp_p);
+}
+
+
+/* Function: void sdp_debug(sdp_t *sdp_p, sdp_debug_e debug_type,
+ * tinybool my_bool);
+ * Description: Define the type of debug for this particular SDP structure.
+ * By default, each SDP description has the settings that are
+ * set for the application.
+ * Valid debug types are ERRORS, WARNINGS, and TRACE. Each
+ * debug type can be turned on/off individually. The
+ * debug level can be redefined at any time.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * debug_type Specifies the debug type being enabled/disabled.
+ * my_bool Defines whether the debug should be enabled or not.
+ * Returns: Nothing.
+ */
+void sdp_debug (sdp_t *sdp_p, sdp_debug_e debug_type, tinybool debug_flag)
+{
+ if (!sdp_p) {
+ return;
+ }
+
+ if (debug_type < SDP_MAX_DEBUG_TYPES) {
+ sdp_p->debug_flag[debug_type] = debug_flag;
+ }
+}
+
+
+/* Function: void sdp_set_string_debug(sdp_t *sdp_p, char *debug_str)
+ * Description: Define a string to be associated with all debug output
+ * for this SDP. The string will be copied into the SDP
+ * structure and so the library will not be dependent on
+ * the application's memory for this string.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description.
+ * debug_str Pointer to a string that should be printed out
+ * with every debug msg.
+ * Returns: Nothing.
+ */
+void sdp_set_string_debug (sdp_t *sdp_p, const char *debug_str)
+{
+ if (!sdp_p) {
+ return;
+ }
+
+ sstrncpy(sdp_p->debug_str, debug_str, sizeof(sdp_p->debug_str));
+}
+
+
+/* Function: sdp_validate_sdp
+ * Description: Validate an SDP structure.
+ * Parameters: sdp_p The SDP handle of the struct to validate.
+ * Returns: A result value indicating if the validation was successful.
+ * If not, what type of error was encountered.
+ */
+sdp_result_e sdp_validate_sdp (sdp_t *sdp_p)
+{
+ int i;
+ uint16_t num_media_levels;
+
+ /* Need to validate c= info is specified at session level or
+ * at all m= levels.
+ */
+ if (sdp_connection_valid((void *)sdp_p, SDP_SESSION_LEVEL) == FALSE) {
+ num_media_levels = sdp_get_num_media_lines((void *)sdp_p);
+ for (i=1; i <= num_media_levels; i++) {
+ if (sdp_connection_valid((void *)sdp_p, (unsigned short)i) == FALSE) {
+ sdp_parse_error(sdp_p,
+ "%s c= connection line not specified for "
+ "every media level, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+ }
+ }
+
+ /* Validate required lines were specified */
+ if ((sdp_owner_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->owner_reqd == TRUE)) {
+ sdp_parse_error(sdp_p,
+ "%s o= owner line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ if ((sdp_session_name_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->session_name_reqd == TRUE)) {
+ sdp_parse_error(sdp_p,
+ "%s s= session name line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ if ((sdp_timespec_valid((void *)sdp_p) == FALSE) &&
+ (sdp_p->conf_p->timespec_reqd == TRUE)) {
+ sdp_parse_error(sdp_p,
+ "%s t= timespec line not specified, validation failed.",
+ sdp_p->debug_str);
+ return (SDP_FAILURE);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/* Function: sdp_parse
+ * Description: Parse an SDP description in the specified buffer.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * bufp Pointer to the buffer containing the SDP
+ * description to parse.
+ * len The length of the buffer.
+ * Returns: A result value indicating if the parse was successful and
+ * if not, what type of error was encountered. The
+ * information from the parse is stored in the sdp_p structure.
+ */
+sdp_result_e sdp_parse (sdp_t *sdp_p, const char *buf, size_t len)
+{
+ uint8_t i;
+ uint16_t cur_level = SDP_SESSION_LEVEL;
+ const char *ptr;
+ const char *next_ptr = NULL;
+ char *line_end;
+ sdp_token_e last_token = SDP_TOKEN_V;
+ sdp_result_e result = SDP_SUCCESS;
+ tinybool parse_done = FALSE;
+ tinybool end_found = FALSE;
+ tinybool first_line = TRUE;
+ tinybool unrec_token = FALSE;
+ const char **bufp = &buf;
+
+ if (!sdp_p) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if ((bufp == NULL) || (*bufp == NULL)) {
+ return (SDP_NULL_BUF_PTR);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Trace SDP Parse:", sdp_p->debug_str);
+ }
+
+ next_ptr = *bufp;
+ sdp_p->conf_p->num_parses++;
+
+ /* Initialize the last valid capability instance to zero. Used
+ * to help in parsing X-cpar attrs. */
+ sdp_p->cap_valid = FALSE;
+ sdp_p->last_cap_inst = 0;
+
+ sdp_p->parse_line = 0;
+
+ /* We want to try to find the end of the SDP description, even if
+ * we find a parsing error.
+ */
+ while (!end_found) {
+ /* If the last char of this line goes beyond the end of the buffer,
+ * we don't parse it.
+ */
+ ptr = next_ptr;
+ sdp_p->parse_line++;
+ line_end = sdp_findchar(ptr, "\n");
+ if ((line_end >= (*bufp + len)) ||
+ (*line_end == '\0')) {
+ /* As this does not update the result value the SDP up to this point
+ * is still accept as valid. So encountering this is not treated as
+ * an error.
+ */
+ sdp_parse_error(sdp_p,
+ "%s End of line beyond end of buffer.",
+ sdp_p->debug_str);
+ CSFLogError(logTag, "SDP: Invalid SDP, no \\n (len %u): %*s",
+ (unsigned)len, (int)len, *bufp);
+ end_found = TRUE;
+ break;
+ }
+
+ /* Print the line if we're tracing. */
+ if ((parse_done == FALSE) &&
+ (sdp_p->debug_flag[SDP_DEBUG_TRACE])) {
+ SDP_PRINT("%s ", sdp_p->debug_str);
+
+ SDP_PRINT("%*s", (int)(line_end - ptr), ptr);
+
+ }
+
+ /* Find out which token this line has, if any. */
+ for (i=0; i < SDP_MAX_TOKENS; i++) {
+ if (strncmp(ptr, sdp_token[i].name, SDP_TOKEN_LEN) == 0) {
+ break;
+ }
+ }
+ if (i == SDP_MAX_TOKENS) {
+ /* See if the second char on the next line is an '=' char.
+ * If so, we note this as an unrecognized token line. */
+ if (ptr[1] == '=') {
+ unrec_token = TRUE;
+ }
+ if (first_line == TRUE) {
+ sdp_parse_error(sdp_p,
+ "%s Attempt to parse text not recognized as "
+ "SDP text, parse fails.", sdp_p->debug_str);
+ /* If we haven't already printed out the line we
+ * were trying to parse, do it now.
+ */
+ if (!sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s ", sdp_p->debug_str);
+ SDP_PRINT("%*s", (int)(line_end - ptr), ptr);
+ }
+ sdp_p->conf_p->num_not_sdp_desc++;
+ return (SDP_NOT_SDP_DESCRIPTION);
+ } else {
+ end_found = TRUE;
+ break;
+ }
+ }
+
+ /* This is the beginning of a new SDP description. */
+ if ((first_line != TRUE) && (i == SDP_TOKEN_V)) {
+ end_found = TRUE;
+ break;
+ }
+
+ /* Advance the next ptr to one char beyond the end of the line. */
+ next_ptr = line_end + 1;
+ if (next_ptr >= (*bufp + len)) {
+ end_found = TRUE;
+ }
+
+ /* If we've finished parsing and are just looking for the end of
+ * the SDP description, we don't need to do anything else here.
+ */
+ if (parse_done == TRUE) {
+ continue;
+ }
+
+ /* Only certain tokens are valid at the media level. */
+ if (cur_level != SDP_SESSION_LEVEL) {
+ if ((i != SDP_TOKEN_I) && (i != SDP_TOKEN_C) &&
+ (i != SDP_TOKEN_B) && (i != SDP_TOKEN_K) &&
+ (i != SDP_TOKEN_A) && (i != SDP_TOKEN_M)) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid token %s found at media level",
+ sdp_p->debug_str, sdp_token[i].name);
+ continue;
+ }
+ }
+
+ /* Verify the token ordering. */
+ if (first_line == TRUE) {
+ if (i != SDP_TOKEN_V) {
+ if (sdp_p->conf_p->version_reqd == TRUE) {
+ sdp_parse_error(sdp_p,
+ "%s First line not v=, parse fails",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_token_order++;
+ result = SDP_INVALID_TOKEN_ORDERING;
+ parse_done = TRUE;
+ } else {
+ last_token = (sdp_token_e)i;
+ }
+ } else {
+ last_token = (sdp_token_e)i;
+ }
+ first_line = FALSE;
+ } else {
+ if (i < last_token) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: Invalid token ordering detected, "
+ "token %s found after token %s", sdp_p->debug_str,
+ sdp_token[i].name, sdp_token[last_token].name);
+ }
+ }
+
+ /* Finally parse the line. */
+ ptr += SDP_TOKEN_LEN;
+ result = sdp_token[i].parse_func(sdp_p, cur_level, (const char *)ptr);
+ last_token = (sdp_token_e)i;
+ if (last_token == SDP_TOKEN_M) {
+ if (cur_level == SDP_SESSION_LEVEL) {
+ cur_level = 1;
+ } else {
+ cur_level++;
+ }
+ /* The token ordering can start again at i= */
+ last_token = (sdp_token_e)(SDP_TOKEN_I - 1);
+ }
+ if (result != SDP_SUCCESS) {
+ parse_done = TRUE;
+ }
+
+ /* Skip the new line char at the end of this line and see if
+ * this is the end of the buffer.
+ */
+ if ((line_end + 1) == (*bufp + len)) {
+ end_found = TRUE;
+ }
+ }
+
+ /* If we found no valid lines, return an error. */
+ if (first_line == TRUE) {
+ sdp_p->conf_p->num_not_sdp_desc++;
+ return (SDP_NOT_SDP_DESCRIPTION);
+ }
+
+ /* If no errors were found yet, validate the overall sdp. */
+ if (result == SDP_SUCCESS) {
+ result = sdp_validate_sdp(sdp_p);
+ }
+ /* Return the pointer where we left off. */
+ *bufp = next_ptr;
+ /* If the SDP is valid, but the next line following was an
+ * unrecognized <token>= line, indicate this on the return. */
+ if ((result == SDP_SUCCESS) && (unrec_token == TRUE)) {
+ return (SDP_UNRECOGNIZED_TOKEN);
+ } else {
+ return (result);
+ }
+}
+
+
+/* Function: sdp_build
+ * Description: Build an SDP description in the specified buffer based
+ * on the information in the given SDP structure.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * fs A flex_string where the SDP description should be built.
+ * Returns: A result value indicating if the build was successful and
+ * if not, what type of error was encountered - e.g.,
+ * description was too long for the given buffer.
+ */
+sdp_result_e sdp_build (sdp_t *sdp_p, flex_string *fs)
+{
+ int i, j;
+ sdp_result_e result = SDP_SUCCESS;
+
+ if (!sdp_p) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ if (!fs) {
+ return (SDP_NULL_BUF_PTR);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Trace SDP Build:", sdp_p->debug_str);
+ }
+
+ sdp_p->conf_p->num_builds++;
+
+ for (i=0; ((i < SDP_TOKEN_M) &&
+ (result == SDP_SUCCESS)); i++) {
+ result = sdp_token[i].build_func(sdp_p, SDP_SESSION_LEVEL, fs);
+ /* ok not to check buffer space (yet) as the if() checks it */
+ }
+ /* If the session level was ok, build the media lines. */
+ if (result == SDP_SUCCESS) {
+ for (i=1; ((i <= sdp_p->mca_count) &&
+ (result == SDP_SUCCESS)); i++) {
+ result = sdp_token[SDP_TOKEN_M].build_func(sdp_p, (uint16_t)i, fs);
+
+ /* ok not to check buffer space (yet) as the for() checks it */
+ for (j=SDP_TOKEN_I;
+ ((j < SDP_TOKEN_M) && (result == SDP_SUCCESS));
+ j++) {
+ if ((j == SDP_TOKEN_U) || (j == SDP_TOKEN_E) ||
+ (j == SDP_TOKEN_P) || (j == SDP_TOKEN_T) ||
+ (j == SDP_TOKEN_R) || (j == SDP_TOKEN_Z)) {
+ /* These tokens not valid at media level. */
+ continue;
+ }
+ result = sdp_token[j].build_func(sdp_p, (uint16_t)i, fs);
+ /* ok not to check buffer space (yet) as the for() checks it */
+ }
+ }
+ }
+
+ return (result);
+}
+
+/* Function: sdp_free_description
+ * Description: Free an SDP description and all memory associated with it.
+ * Parameters: sdp_p The SDP handle returned by sdp_init_description
+ * Returns: A result value indicating if the free was successful and
+ * if not, what type of error was encountered - e.g., sdp_p
+ * was invalid and didn't point to an SDP structure.
+*/
+sdp_result_e sdp_free_description (sdp_t *sdp_p)
+{
+ sdp_timespec_t *time_p, *next_time_p;
+ sdp_attr_t *attr_p, *next_attr_p;
+ sdp_mca_t *mca_p, *next_mca_p;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+
+ if (!sdp_p) {
+ return (SDP_INVALID_SDP_PTR);
+ }
+
+ /* Free the config structure */
+ sdp_free_config(sdp_p->conf_p);
+
+ /* Free any timespec structures - should be only one since
+ * this is all we currently support.
+ */
+ time_p = sdp_p->timespec_p;
+ while (time_p != NULL) {
+ next_time_p = time_p->next_p;
+ SDP_FREE(time_p);
+ time_p = next_time_p;
+ }
+
+ bw_p = &(sdp_p->bw);
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ SDP_FREE(bw_data_p);
+ bw_data_p = bw_p->bw_data_list;
+ }
+
+ /* Free any session attr structures */
+ attr_p = sdp_p->sess_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+
+ /* Free any mca structures */
+ mca_p = sdp_p->mca_p;
+ while (mca_p != NULL) {
+ next_mca_p = mca_p->next_p;
+
+ /* Free any media attr structures */
+ attr_p = mca_p->media_attrs_p;
+ while (attr_p != NULL) {
+ next_attr_p = attr_p->next_p;
+ sdp_free_attr(attr_p);
+ attr_p = next_attr_p;
+ }
+
+ /* Free the media profiles struct if allocated. */
+ if (mca_p->media_profiles_p != NULL) {
+ SDP_FREE(mca_p->media_profiles_p);
+ }
+
+ bw_p = &(mca_p->bw);
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p != NULL) {
+ bw_p->bw_data_list = bw_data_p->next_p;
+ SDP_FREE(bw_data_p);
+ bw_data_p = bw_p->bw_data_list;
+ }
+
+ SDP_FREE(mca_p);
+ mca_p = next_mca_p;
+ }
+
+ SDP_FREE(sdp_p);
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_parse_error
+ * Send SDP parsing errors to log and up to peerconnection
+ */
+void sdp_parse_error(sdp_t* sdp, const char *format, ...) {
+ flex_string fs;
+ va_list ap;
+
+ flex_string_init(&fs);
+
+ va_start(ap, format);
+ flex_string_vsprintf(&fs, format, ap);
+ va_end(ap);
+
+ CSFLogError("SDP Parse", "SDP Parse Error %s, line %u", fs.buffer,
+ sdp->parse_line);
+
+ if (sdp->conf_p->error_handler) {
+ sdp->conf_p->error_handler(sdp->conf_p->error_handler_context,
+ sdp->parse_line,
+ fs.buffer);
+ }
+
+ flex_string_free(&fs);
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h b/media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h
new file mode 100644
index 000000000..6e4dd8c64
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h
@@ -0,0 +1,27 @@
+/* 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 _SDP_OS_DEFS_H_
+#define _SDP_OS_DEFS_H_
+
+#include <stdlib.h>
+
+#include "cpr_types.h"
+#include "cpr_string.h"
+
+
+#define SDP_PRINT(format, ...) CSFLogError("sdp" , format , ## __VA_ARGS__ )
+
+/* Use operating system malloc */
+#define SDP_MALLOC(x) calloc(1, (x))
+#define SDP_FREE free
+
+typedef uint8_t tinybool;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+#ifndef __GNUC_STDC_INLINE__
+#define inline
+#endif
+
+#endif /* _SDP_OS_DEFS_H_ */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h b/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h
new file mode 100644
index 000000000..a98f4b119
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_private.h
@@ -0,0 +1,364 @@
+/* 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 _SIPCC_SDP_PRIVATE_H_
+#define _SIPCC_SDP_PRIVATE_H_
+
+
+#include "sdp.h"
+
+extern const sdp_attrarray_t sdp_attr[];
+extern const sdp_namearray_t sdp_media[];
+extern const sdp_namearray_t sdp_nettype[];
+extern const sdp_namearray_t sdp_addrtype[];
+extern const sdp_namearray_t sdp_transport[];
+extern const sdp_namearray_t sdp_encrypt[];
+extern const sdp_namearray_t sdp_payload[];
+extern const sdp_namearray_t sdp_t38_rate[];
+extern const sdp_namearray_t sdp_t38_udpec[];
+extern const sdp_namearray_t sdp_qos_strength[];
+extern const sdp_namearray_t sdp_qos_direction[];
+extern const sdp_namearray_t sdp_qos_status_type[];
+extern const sdp_namearray_t sdp_curr_type[];
+extern const sdp_namearray_t sdp_des_type[];
+extern const sdp_namearray_t sdp_conf_type[];
+extern const sdp_namearray_t sdp_mediadir_role[];
+extern const sdp_namearray_t sdp_fmtp_codec_param[];
+extern const sdp_namearray_t sdp_fmtp_codec_param_val[];
+extern const sdp_namearray_t sdp_silencesupp_pref[];
+extern const sdp_namearray_t sdp_silencesupp_siduse[];
+extern const sdp_namearray_t sdp_srtp_context_crypto_suite[];
+extern const sdp_namearray_t sdp_bw_modifier_val[];
+extern const sdp_namearray_t sdp_group_attr_val[];
+extern const sdp_namearray_t sdp_src_filter_mode_val[];
+extern const sdp_namearray_t sdp_rtcp_unicast_mode_val[];
+extern const sdp_namearray_t sdp_rtcp_fb_type_val[];
+extern const sdp_namearray_t sdp_rtcp_fb_nack_type_val[];
+extern const sdp_namearray_t sdp_rtcp_fb_ack_type_val[];
+extern const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[];
+extern const sdp_namearray_t sdp_setup_type_val[];
+extern const sdp_namearray_t sdp_connection_type_val[];
+
+
+extern const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[];
+/* Function Prototypes */
+
+/* sdp_access.c */
+extern sdp_mca_t *sdp_find_media_level(sdp_t *sdp_p, uint16_t level);
+extern sdp_bw_data_t* sdp_find_bw_line (sdp_t *sdp_ptr, uint16_t level, uint16_t inst_num);
+
+/* sdp_attr.c */
+extern sdp_result_e
+sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, uint16_t level,
+ const char *ptr);
+extern sdp_result_e sdp_parse_attr_simple_string(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_string(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_u32(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_u32(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_bool(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_simple_bool(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_maxprate(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_parse_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_curr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_des(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_conf(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_transport_map(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_transport_map(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_t38_ratemgmt(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_t38_ratemgmt(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_rtcp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_rtcp(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_silencesupp(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_silencesupp(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_srtpcontext(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_srtpcontext(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_rtcp_fb(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ const char *ptr);
+extern sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
+ sdp_attr_t *attr_p,
+ flex_string *fs);
+extern sdp_result_e sdp_parse_attr_mptime(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_mptime(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_x_sidin(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_sidin(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_x_sidout(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_sidout(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_x_confid(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_x_confid(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_group(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_group(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_source_filter(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_source_filter(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_parse_attr_rtcp_unicast(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_rtcp_unicast(
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+
+extern sdp_result_e sdp_build_attr_ice_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_ice_attr (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+
+extern sdp_result_e sdp_build_attr_simple_flag (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
+extern sdp_result_e sdp_parse_attr_simple_flag (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+
+extern sdp_result_e sdp_parse_attr_complete_line (
+ sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_parse_attr_long_line(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, const char *ptr);
+extern sdp_result_e sdp_build_attr_long_line(sdp_t *sdp_p,
+ sdp_attr_t *attr_p, flex_string *fs);
+
+/* sdp_attr_access.c */
+extern void sdp_free_attr(sdp_attr_t *attr_p);
+extern sdp_result_e sdp_find_attr_list(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_t **attr_p, char *fname);
+extern sdp_attr_t *sdp_find_attr(sdp_t *sdp_p, uint16_t level, uint8_t cap_num,
+ sdp_attr_e attr_type, uint16_t inst_num);
+extern sdp_attr_t *sdp_find_capability(sdp_t *sdp_p, uint16_t level, uint8_t cap_num);
+
+/* sdp_main.c */
+extern const char *sdp_get_attr_name(sdp_attr_e attr_type);
+extern const char *sdp_get_media_name(sdp_media_e media_type);
+extern const char *sdp_get_network_name(sdp_nettype_e network_type);
+extern const char *sdp_get_address_name(sdp_addrtype_e addr_type);
+extern const char *sdp_get_transport_name(sdp_transport_e transport_type);
+extern const char *sdp_get_encrypt_name(sdp_encrypt_type_e encrypt_type);
+extern const char *sdp_get_payload_name(sdp_payload_e payload);
+extern const char *sdp_get_t38_ratemgmt_name(sdp_t38_ratemgmt_e rate);
+extern const char *sdp_get_t38_udpec_name(sdp_t38_udpec_e udpec);
+extern const char *sdp_get_qos_strength_name(sdp_qos_strength_e strength);
+extern const char *sdp_get_qos_direction_name(sdp_qos_dir_e direction);
+extern const char *sdp_get_qos_status_type_name(sdp_qos_status_types_e status_type);
+extern const char *sdp_get_curr_type_name(sdp_curr_type_e curr_type);
+extern const char *sdp_get_des_type_name(sdp_des_type_e des_type);
+extern const char *sdp_get_conf_type_name(sdp_conf_type_e conf_type);
+extern const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role);
+extern const char *sdp_get_silencesupp_pref_name(sdp_silencesupp_pref_e pref);
+extern const char *sdp_get_silencesupp_siduse_name(sdp_silencesupp_siduse_e
+ siduse);
+
+extern const char *sdp_get_group_attr_name(sdp_group_attr_e group_attr);
+extern const char *sdp_get_src_filter_mode_name(sdp_src_filter_mode_e type);
+extern const char *sdp_get_rtcp_unicast_mode_name(sdp_rtcp_unicast_mode_e type);
+
+/* sdp_tokens.c */
+extern sdp_result_e sdp_parse_version(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_version(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_owner(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_owner(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_sessname(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_sessname(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_sessinfo(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_sessinfo(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_uri(sdp_t *sdp_p, uint16_t token, const char *ptr);
+extern sdp_result_e sdp_build_uri(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_email(sdp_t *sdp_p, uint16_t token, const char *ptr);
+extern sdp_result_e sdp_build_email(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_phonenum(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_phonenum(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_connection(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_connection(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_bandwidth(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_bandwidth(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_timespec(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_timespec(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_repeat_time(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_repeat_time(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_timezone_adj(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_timezone_adj(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_encryption(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_encryption(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_media(sdp_t *sdp_p, uint16_t token, const char *ptr);
+extern sdp_result_e sdp_build_media(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, uint16_t token,
+ const char *ptr);
+extern sdp_result_e sdp_build_attribute(sdp_t *sdp_p, uint16_t token, flex_string *fs);
+
+extern void sdp_parse_payload_types(sdp_t *sdp_p, sdp_mca_t *mca_p,
+ const char *ptr);
+extern sdp_result_e sdp_parse_multiple_profile_payload_types(sdp_t *sdp_p,
+ sdp_mca_t *mca_p,
+ const char *ptr);
+extern sdp_result_e
+sdp_parse_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ const char *ptr);
+
+extern sdp_result_e
+sdp_build_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p,
+ flex_string *fs);
+
+
+/* sdp_utils.c */
+extern sdp_mca_t *sdp_alloc_mca(uint32_t line);
+extern tinybool sdp_validate_maxprate(const char *string_parm);
+extern char *sdp_findchar(const char *ptr, char *char_list);
+extern const char *sdp_getnextstrtok(const char *str, char *tokenstr, unsigned tokenstr_len,
+ const char *delim, sdp_result_e *result);
+extern uint32_t sdp_getnextnumtok(const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result);
+extern uint32_t sdp_getnextnumtok_or_null(const char *str, const char **str_end,
+ const char *delim, tinybool *null_ind,
+ sdp_result_e *result);
+extern tinybool sdp_getchoosetok(const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result);
+
+extern
+tinybool verify_sdescriptions_mki(char *buf, char *mkiVal, uint16_t *mkiLen);
+
+extern
+tinybool verify_sdescriptions_lifetime(char *buf);
+
+/* sdp_services_xxx.c */
+extern void sdp_dump_buffer(char *_ptr, int _size_bytes);
+
+tinybool sdp_checkrange(sdp_t *sdp, char *num, ulong* lval);
+
+#endif /* _SDP_PRIVATE_H_ */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_services_unix.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_services_unix.c
new file mode 100644
index 000000000..8f43adc43
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_services_unix.c
@@ -0,0 +1,41 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+/******************************************************************/
+/* Required Platform Routines */
+/* */
+/* These routines are called from the common SDP code. */
+/* They must be provided for each platform. */
+/* */
+/******************************************************************/
+
+/*
+ * sdp_dump_buffer
+ *
+ * Utility to send _size_bytes of data from the string
+ * pointed to by _ptr to the buginf function. This may make
+ * multiple buginf calls if the buffer is too large for buginf.
+ */
+void sdp_dump_buffer (char * _ptr, int _size_bytes)
+{
+ CSFLogDebug("sdp", "%s", _ptr);
+}
+
+/******************************************************************/
+/* */
+/* Platform Specific Routines */
+/* */
+/* These routines are only used in this particular platform. */
+/* They are called from the required platform specific */
+/* routines provided below, not from the common SDP code. */
+/* */
+/******************************************************************/
+
+/* There are currently no platform specific routines required. */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_services_win32.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_services_win32.c
new file mode 100644
index 000000000..1815abbfe
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_services_win32.c
@@ -0,0 +1,40 @@
+/* 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/. */
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+
+/******************************************************************/
+/* Required Platform Routines */
+/* */
+/* These routines are called from the common SDP code. */
+/* They must be provided for each platform. */
+/* */
+/******************************************************************/
+
+/*
+ * sdp_dump_buffer
+ *
+ * Utility to send _size_bytes of data from the string
+ * pointed to by _ptr to the buginf function. This may make
+ * multiple buginf calls if the buffer is too large for buginf.
+ */
+void sdp_dump_buffer (char * _ptr, int _size_bytes)
+{
+ CSFLogDebug("sdp", _ptr);
+}
+
+/******************************************************************/
+/* */
+/* Platform Specific Routines */
+/* */
+/* These routines are only used in this particular platform. */
+/* They are called from the required platform specific */
+/* routines provided below, not from the common SDP code. */
+/* */
+/******************************************************************/
+
+/* There are currently no platform specific routines required. */
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
new file mode 100644
index 000000000..a002f9a73
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_token.c
@@ -0,0 +1,1812 @@
+/* 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/. */
+
+#include <errno.h>
+
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+#include "prprf.h"
+
+static const char *logTag = "sdp_token";
+
+#define MCAST_STRING_LEN 4
+
+
+sdp_result_e sdp_parse_version (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ sdp_result_e result = SDP_FAILURE;
+
+ sdp_p->version = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if ((result != SDP_SUCCESS) || (sdp_p->version != SDP_CURRENT_VERSION)) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid version (%u) found, parse failed.",
+ sdp_p->debug_str, (unsigned)sdp_p->version);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse version line successful, version %u",
+ sdp_p->debug_str, (unsigned)sdp_p->version);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_version (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ if (sdp_p->version == SDP_INVALID_VALUE) {
+ if (sdp_p->conf_p->version_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid version for v= line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* v= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "v=%u\r\n", (unsigned)sdp_p->version);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built v= version line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+static sdp_result_e sdp_verify_unsigned(const char *ptr, uint64_t max_value)
+{
+ uint64_t numeric_value;
+ /* Checking for only numbers since PR_sscanf will ignore trailing
+ characters */
+ size_t end = strspn(ptr, "0123456789");
+
+ if (ptr[end] != '\0')
+ return SDP_INVALID_PARAMETER;
+
+ if (PR_sscanf(ptr, "%llu", &numeric_value) != 1)
+ return SDP_INVALID_PARAMETER;
+
+ if (numeric_value > max_value)
+ return SDP_INVALID_PARAMETER;
+
+ return SDP_SUCCESS;
+}
+
+sdp_result_e sdp_parse_owner (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+ /* The spec says this:
+
+ The numeric value of the session id
+ and version in the o line MUST be representable with a 64 bit signed
+ integer. The initial value of the version MUST be less than
+ (2**62)-1, to avoid rollovers.
+ */
+ const uint64_t max_value_sessid = ((((uint64_t) 1) << 63) - 1);
+ /* Do not check that this is 2^62 - 1; that's just the limit on
+ * the initial version, not every version number. */
+ const uint64_t max_value_version = ((((uint64_t) 1) << 63) - 1);
+
+ if (sdp_p->owner_name[0] != '\0') {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: More than one o= line specified.",
+ sdp_p->debug_str);
+ }
+
+ /* Find the owner name. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_name, sizeof(sdp_p->owner_name), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No owner name specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner session id. This is a numeric field but is
+ * stored as a string since it may be 64 bit.
+ */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_sessid, sizeof(sdp_p->owner_sessid), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the sessid is numeric, even though we store it as
+ * a string.
+ */
+ result = sdp_verify_unsigned(sdp_p->owner_sessid, max_value_sessid);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid owner session id specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner version. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_version, sizeof(sdp_p->owner_version), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the version is numeric, even though we store it as
+ * a string.
+ */
+ result = sdp_verify_unsigned(sdp_p->owner_version, max_value_version);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid owner version specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No owner network type specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ sdp_p->owner_network_type = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ sdp_p->owner_network_type = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (sdp_p->owner_network_type == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Owner network type unsupported (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No owner address type specified for o=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ sdp_p->owner_addr_type = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ sdp_p->owner_addr_type = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if ((sdp_p->owner_addr_type == SDP_AT_UNSUPPORTED) &&
+ (sdp_p->owner_network_type != SDP_NT_ATM)) {
+ sdp_parse_error(sdp_p,
+ "%s Owner address type unsupported (%s)",
+ sdp_p->debug_str, tmp);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find the owner address. */
+ ptr = sdp_getnextstrtok(ptr, sdp_p->owner_addr, sizeof(sdp_p->owner_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No owner address specified.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse owner: name %s, session id %s, version %s",
+ sdp_p->debug_str, sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version);
+ SDP_PRINT("%s network %s, address type %s, "
+ "address %s", sdp_p->debug_str,
+ sdp_get_network_name(sdp_p->owner_network_type),
+ sdp_get_address_name(sdp_p->owner_addr_type),
+ sdp_p->owner_addr);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_owner (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ if ((sdp_p->owner_name[0] == '\0') ||
+ (sdp_p->owner_network_type >= SDP_MAX_NETWORK_TYPES) ||
+ (sdp_p->owner_addr_type >= SDP_MAX_ADDR_TYPES) ||
+ (sdp_p->owner_addr[0] == '\0')) {
+
+ if((sdp_p->owner_network_type == SDP_NT_ATM) &&
+ (sdp_p->owner_addr_type == SDP_AT_INVALID)) {
+ flex_string_sprintf(fs, "o=%s %s %s %s - -\r\n",
+ sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version,
+ sdp_get_network_name(sdp_p->owner_network_type));
+ }
+
+ if (sdp_p->conf_p->owner_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for o= owner line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* o= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "o=%s %s %s %s %s %s\r\n",
+ sdp_p->owner_name, sdp_p->owner_sessid,
+ sdp_p->owner_version,
+ sdp_get_network_name(sdp_p->owner_network_type),
+ sdp_get_address_name(sdp_p->owner_addr_type),
+ sdp_p->owner_addr);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built o= owner line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_sessname (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int str_len;
+ char *endptr;
+
+ if (sdp_p->sessname[0] != '\0') {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: More than one s= line specified.",
+ sdp_p->debug_str);
+ }
+
+ endptr = sdp_findchar(ptr, "\r\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No session name specified.",
+ sdp_p->debug_str);
+ }
+ str_len = MIN(endptr - ptr, SDP_MAX_STRING_LEN);
+ sstrncpy(sdp_p->sessname, ptr, str_len+1);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse session name, %s",
+ sdp_p->debug_str, sdp_p->sessname);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_sessname (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ if (sdp_p->sessname[0] == '\0') {
+ if (sdp_p->conf_p->session_name_reqd == TRUE) {
+ CSFLogError(logTag, "%s No param defined for s= session name line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* s= line is not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ flex_string_sprintf(fs, "s=%s\r\n", sdp_p->sessname);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built s= session name line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+/* We don't want to store the session info, but we do want to validate
+ * that at most one i= line exists at each level and if the line exists
+ * there should be a parameter.
+ */
+sdp_result_e sdp_parse_sessinfo (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ if (sdp_p->sessinfo_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: More than one i= line specified.",
+ sdp_p->debug_str);
+ }
+ sdp_p->sessinfo_found = TRUE;
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ if (mca_p->sessinfo_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: More than one i= line specified"
+ " for media line %u.", sdp_p->debug_str, (unsigned)level);
+ }
+ mca_p->sessinfo_found = TRUE;
+ }
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No session info specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed session info line.", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_sessinfo (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build session info line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_uri (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+
+ if (sdp_p->uri_found == TRUE) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s Warning: More than one u= line specified.",
+ sdp_p->debug_str);
+ }
+ sdp_p->uri_found = TRUE;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No URI info specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed URI line.", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_uri (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build URI line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_email (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No email info specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse email line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_email (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build email line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_phonenum (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No phone number info specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse phone number line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_phonenum (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build phone number line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_connection (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int i;
+ const char *slash_ptr;
+ sdp_result_e result;
+ sdp_conn_t *conn_p;
+ sdp_mca_t *mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char mcast_str[MCAST_STRING_LEN];
+ int mcast_bits;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ /* See if the c= line is already defined at this level. We don't
+ * currently support multihoming and so we only support one c= at
+ * each level.
+ */
+ if (conn_p->nettype != SDP_NT_INVALID) {
+ sdp_p->conf_p->num_invalid_token_order++;
+ sdp_parse_error(sdp_p,
+ "%s c= line specified twice at same level, "
+ "parse failed.", sdp_p->debug_str);
+ return (SDP_INVALID_TOKEN_ORDERING);
+ }
+
+ /* Find the connection network type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No connection network type specified for c=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ conn_p->nettype = SDP_NT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
+ sdp_nettype[i].strlen) == 0) {
+ if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
+ conn_p->nettype = (sdp_nettype_e)i;
+ }
+ }
+ }
+ if (conn_p->nettype == SDP_NT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Connection network type unsupported "
+ "(%s) for c=.", sdp_p->debug_str, tmp);
+ }
+
+ /* Find the connection address type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ if (conn_p->nettype == SDP_NT_ATM) {
+ /* If the nettype is ATM, addr type and addr are not reqd */
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse connection: network %s", sdp_p->debug_str,
+ sdp_get_network_name(conn_p->nettype));
+ }
+ return (SDP_SUCCESS);
+ } else {
+ sdp_parse_error(sdp_p,
+ "%s No connection address type specified for "
+ "c=.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+ conn_p->addrtype = SDP_AT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
+ sdp_addrtype[i].strlen) == 0) {
+ if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
+ conn_p->addrtype = (sdp_addrtype_e)i;
+ }
+ }
+ }
+ if (conn_p->addrtype == SDP_AT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Connection address type unsupported "
+ "(%s) for c=.", sdp_p->debug_str, tmp);
+ }
+
+ /* Find the connection address. */
+ ptr = sdp_getnextstrtok(ptr, conn_p->conn_addr, sizeof(conn_p->conn_addr), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No connection address specified for c=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ /* We currently only support addrs containing '/'s for EPN addrs.
+ * For other addrs this would indicate multicast addrs. */
+ /* Multicast host group addresses are defined to be the IP addresses
+ * whose high-order four bits are 1110, giving an address range from
+ * 224.0.0.0 through 239.255.255.255
+ */
+ /* multicast addr check */
+ sstrncpy (mcast_str, conn_p->conn_addr, MCAST_STRING_LEN);
+
+ if (conn_p->addrtype == SDP_AT_IP4) {
+ errno = 0;
+ strtoul_result = strtoul(mcast_str, &strtoul_end, 10);
+
+ if (errno || mcast_str == strtoul_end || strtoul_result > 255) {
+ sdp_parse_error(sdp_p,
+ "%s Error parsing address %s for mcast.",
+ sdp_p->debug_str, mcast_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+
+ mcast_bits = (int) strtoul_result;
+ if ((mcast_bits >= SDP_MIN_MCAST_ADDR_HI_BIT_VAL ) &&
+ (mcast_bits <= SDP_MAX_MCAST_ADDR_HI_BIT_VAL)) {
+ SDP_PRINT("%s Parsed to be a multicast address with mcast bits %d",
+ sdp_p->debug_str, mcast_bits);
+ conn_p->is_multicast = TRUE;
+ }
+ }
+
+ if (conn_p->addrtype != SDP_AT_EPN) {
+ slash_ptr = sdp_findchar(conn_p->conn_addr, "/");
+ if (slash_ptr[0] != '\0') {
+ /* this used to rely on the above busted multicast check */
+ SDP_PRINT("%s An address with slash %s",
+ sdp_p->debug_str, conn_p->conn_addr);
+ conn_p->conn_addr[slash_ptr - conn_p->conn_addr] = '\0';
+ slash_ptr++;
+ slash_ptr = sdp_getnextstrtok(slash_ptr, tmp, sizeof(tmp),
+ "/", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No ttl value specified for this multicast addr with a slash",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ errno = 0;
+ strtoul_result = strtoul(tmp, &strtoul_end, 10);
+
+ if (errno || tmp == strtoul_end || conn_p->ttl > SDP_MAX_TTL_VALUE) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid TTL: Value must be in the range 0-255 ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ conn_p->ttl = (int) strtoul_result;
+
+ /* search for num of addresses */
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ slash_ptr = sdp_findchar(slash_ptr, "/");
+ if (slash_ptr != NULL &&
+ slash_ptr[0] != '\0') {
+ SDP_PRINT("%s Found a num addr field for multicast addr %s ",
+ sdp_p->debug_str,slash_ptr);
+ slash_ptr++;
+
+ errno = 0;
+ strtoul_result = strtoul(slash_ptr, &strtoul_end, 10);
+
+ if (errno || slash_ptr == strtoul_end || strtoul_result == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid Num of addresses: Value must be > 0 ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return SDP_INVALID_PARAMETER;
+ }
+
+ conn_p->num_of_addresses = (int) strtoul_result;
+ }
+ }
+ }
+
+ /* See if the address is the choose param and if it's allowed. */
+ if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_CONN_ADDR] == FALSE) &&
+ (strcmp(conn_p->conn_addr, "$") == 0)) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Choose parameter for connection "
+ "address specified but not allowed.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse connection: network %s, address type %s, "
+ "address %s ttl= %u num of addresses = %u",
+ sdp_p->debug_str,
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr, (unsigned)conn_p->ttl, (unsigned)conn_p->num_of_addresses);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_connection (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ sdp_mca_t *mca_p;
+ sdp_conn_t *conn_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ conn_p = &(sdp_p->default_conn);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ conn_p = &(mca_p->conn);
+ }
+
+ if((conn_p->nettype == SDP_NT_ATM ) &&
+ (conn_p->addrtype == SDP_AT_INVALID)) {
+ /*allow c= line to be built without address type and address fields
+ * This is a special case for ATM PVC*/
+ flex_string_sprintf(fs, "c=%s\r\n",
+ sdp_get_network_name(conn_p->nettype));
+ return SDP_SUCCESS;
+ }
+ if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
+ (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
+ (conn_p->conn_addr[0] == '\0')) {
+ /* Connection info isn't set - don't need to build the token. */
+ return (SDP_SUCCESS);
+ }
+
+ if (conn_p->is_multicast) {
+ if (conn_p->num_of_addresses > 1) {
+ flex_string_sprintf(fs, "c=%s %s %s/%u/%u\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr,
+ (unsigned)conn_p->ttl,
+ (unsigned)conn_p->num_of_addresses);
+ } else {
+ flex_string_sprintf(fs, "c=%s %s %s/%u\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr,
+ (unsigned)conn_p->ttl);
+ }
+ } else {
+
+ flex_string_sprintf(fs, "c=%s %s %s\r\n",
+ sdp_get_network_name(conn_p->nettype),
+ sdp_get_address_name(conn_p->addrtype),
+ conn_p->conn_addr);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built c= connection line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_parse_bandwidth
+ *
+ * This function parses a bandwidth field. The parsing is done in accordance
+ * to the following ABNF:
+ *
+ * bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+ * bwtype = 1*(alpha-numeric)
+ * bandwidth = 1*(DIGIT)
+ *
+ * It currently supports three types of valid bwtypes - AS, CT and TIAS
+ */
+sdp_result_e sdp_parse_bandwidth (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int i;
+ sdp_mca_t *mca_p;
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_bw_data_t *new_bw_data_p;
+ sdp_result_e result;
+ char tmp[SDP_MAX_STRING_LEN];
+ sdp_bw_modifier_e bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
+ int bw_val = 0;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse bandwidth line", sdp_p->debug_str);
+ }
+
+ /* Find the bw type (AS, CT or TIAS) */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No bandwidth type specified for b= ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ for (i=0; i < SDP_MAX_BW_MODIFIER_VAL; i++) {
+ if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
+ sdp_bw_modifier_val[i].strlen) == 0) {
+ bw_modifier = (sdp_bw_modifier_e)i;
+ break;
+ }
+ }
+
+ if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
+ /* We don't understand this parameter, so according to RFC4566 sec 5.8
+ * ignore it. */
+ return (SDP_SUCCESS);
+ }
+
+ /* Find the BW type value */
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ if (*ptr == ':') {
+ ptr++;
+ bw_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
+ if ((result != SDP_SUCCESS)) {
+ sdp_parse_error(sdp_p,
+ "%s Error: No BW Value specified ",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ /*
+ * Allocate a new sdp_bw_data_t instance and set it's values from the
+ * input parameters.
+ */
+ new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
+ if (new_bw_data_p == NULL) {
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_NO_RESOURCE);
+ }
+ new_bw_data_p->next_p = NULL;
+ new_bw_data_p->bw_modifier = bw_modifier;
+ new_bw_data_p->bw_val = bw_val;
+
+ /*
+ * Enqueue the sdp_bw_data_t instance at the end of the list of
+ * sdp_bw_data_t instances.
+ */
+ if (bw_p->bw_data_list == NULL) {
+ bw_p->bw_data_list = new_bw_data_p;
+ } else {
+ for (bw_data_p = bw_p->bw_data_list;
+ bw_data_p->next_p != NULL;
+ bw_data_p = bw_data_p->next_p) {
+ ; // Empty For
+ }
+ bw_data_p->next_p = new_bw_data_p;
+ }
+ bw_p->bw_data_count++;
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed bw type %s, value %d", sdp_p->debug_str,
+ sdp_get_bw_modifier_name(new_bw_data_p->bw_modifier),
+ new_bw_data_p->bw_val);
+ }
+
+ return (SDP_SUCCESS);
+}
+
+/*
+ * sdp_build_bandwidth
+ *
+ * Builds *all* the bandwith lines for the specified level.
+ */
+sdp_result_e sdp_build_bandwidth (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ sdp_bw_t *bw_p;
+ sdp_bw_data_t *bw_data_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ bw_p = &(sdp_p->bw);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ bw_p = &(mca_p->bw);
+ }
+
+ bw_data_p = bw_p->bw_data_list;
+ while (bw_data_p) {
+ flex_string_sprintf(fs, "b=%s:%d\r\n",
+ sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
+ bw_data_p->bw_val);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built b=%s:%d bandwidth line", sdp_p->debug_str,
+ sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
+ bw_data_p->bw_val);
+ }
+
+ bw_data_p = bw_data_p->next_p;
+ }
+
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_timespec (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *tmpptr;
+ sdp_result_e result;
+ sdp_timespec_t *timespec_p;
+ sdp_timespec_t *next_timespec_p;
+
+ timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
+ if (timespec_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Validate start and stop times. */
+ ptr = sdp_getnextstrtok(ptr, timespec_p->start_time, sizeof(timespec_p->start_time), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the start_time is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(timespec_p->start_time,
+ (const char **)&tmpptr, " \t", &result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid timespec start time specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(timespec_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ ptr = sdp_getnextstrtok(ptr, timespec_p->stop_time, sizeof(timespec_p->stop_time), " \t", &result);
+ if (result == SDP_SUCCESS) {
+ /* Make sure the start_time is numeric, even though we store it as
+ * a string.
+ */
+ (void)sdp_getnextnumtok(timespec_p->stop_time,
+ (const char **)&tmpptr, " \t", &result);
+ }
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid timespec stop time specified.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(timespec_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Link the new timespec in to the end of the list. */
+ if (sdp_p->timespec_p == NULL) {
+ sdp_p->timespec_p = timespec_p;
+ } else {
+ next_timespec_p = sdp_p->timespec_p;
+ while (next_timespec_p->next_p != NULL) {
+ next_timespec_p = next_timespec_p->next_p;
+ }
+ next_timespec_p->next_p = timespec_p;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_timespec (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ if ((sdp_p->timespec_p == NULL) ||
+ (sdp_p->timespec_p->start_time[0] == '\0') ||
+ (sdp_p->timespec_p->stop_time[0] == '\0')) {
+ if (sdp_p->conf_p->timespec_reqd == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for t= time spec line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ /* t= line not required. */
+ return (SDP_SUCCESS);
+ }
+ }
+
+ /* Note: We only support one t= line currently. */
+ flex_string_sprintf(fs, "t=%s %s\r\n", sdp_p->timespec_p->start_time,
+ sdp_p->timespec_p->stop_time);
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built t= timespec line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_repeat_time (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No repeat time parameters "
+ "specified.", sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parsed repeat time line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_repeat_time (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build repeat time line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_timezone_adj (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ char *endptr;
+
+ endptr = sdp_findchar(ptr, "\n");
+ if (ptr == endptr) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No timezone parameters specified.",
+ sdp_p->debug_str);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse timezone adustment line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_timezone_adj (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ /* Build timezone adjustment line not supported. */
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_encryption (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ int i;
+ sdp_result_e result;
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+ encrypt_p->encrypt_key[0] = '\0';
+
+ /* Find the encryption type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No encryption type specified for k=.",
+ sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ encrypt_p->encrypt_type = SDP_ENCRYPT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_ENCRYPT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_encrypt[i].name,
+ sdp_encrypt[i].strlen) == 0) {
+ encrypt_p->encrypt_type = (sdp_encrypt_type_e)i;
+ break;
+ }
+ }
+ if (encrypt_p->encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Encryption type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+ /* Find the encryption key. */
+ encrypt_p->encrypt_key[0] = '\0';
+ /*sa_ignore NO_NULL_CHK
+ {ptr is valid since the pointer was checked earlier and the
+ function would have exited if NULL.}*/
+ if (*ptr == ':')
+ ptr++;
+ if (encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) {
+ ptr = sdp_getnextstrtok(ptr, encrypt_p->encrypt_key, sizeof(encrypt_p->encrypt_key), " \t", &result);
+ if ((result != SDP_SUCCESS) &&
+ ((encrypt_p->encrypt_type == SDP_ENCRYPT_CLEAR) ||
+ (encrypt_p->encrypt_type == SDP_ENCRYPT_BASE64) ||
+ (encrypt_p->encrypt_type == SDP_ENCRYPT_URI))) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No encryption key specified "
+ "as required.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Parse encryption type %s, key %s", sdp_p->debug_str,
+ sdp_get_encrypt_name(encrypt_p->encrypt_type),
+ encrypt_p->encrypt_key);
+ }
+ return (SDP_SUCCESS);
+}
+
+/* If the encryption info is valid, we build it. Else skip it. */
+sdp_result_e sdp_build_encryption (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ sdp_encryptspec_t *encrypt_p;
+ sdp_mca_t *mca_p;
+
+ if (level == SDP_SESSION_LEVEL) {
+ encrypt_p = &(sdp_p->encrypt);
+ } else {
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+ encrypt_p = &(mca_p->encrypt);
+ }
+
+ if ((encrypt_p->encrypt_type >= SDP_MAX_ENCRYPT_TYPES) ||
+ ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
+ (encrypt_p->encrypt_key[0] == '\0'))) {
+ /* Encryption info isn't set - don't need to build the token. */
+ return (SDP_SUCCESS);
+ }
+
+ flex_string_sprintf(fs, "k=%s",
+ sdp_get_encrypt_name(encrypt_p->encrypt_type));
+
+ if (encrypt_p->encrypt_type == SDP_ENCRYPT_PROMPT) {
+ /* There is no key to print. */
+ flex_string_sprintf(fs, "\r\n");
+ } else {
+ flex_string_sprintf(fs, ":%s\r\n", encrypt_p->encrypt_key);
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built k= encryption line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_parse_media (sdp_t *sdp_p, uint16_t level, const char *ptr)
+{
+ uint16_t i;
+ uint16_t num_port_params=0;
+ int32_t num[SDP_MAX_PORT_PARAMS];
+ tinybool valid_param = FALSE;
+ sdp_result_e result;
+ sdp_mca_t *mca_p;
+ sdp_mca_t *next_mca_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char port[SDP_MAX_STRING_LEN];
+ const char *port_ptr;
+ int32_t sctp_port;
+
+ /* Allocate resource for new media stream. */
+ mca_p = sdp_alloc_mca(sdp_p->parse_line);
+ if (mca_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ return (SDP_NO_RESOURCE);
+ }
+
+ /* Find the media type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No media type specified, parse failed.",
+ sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->media = SDP_MEDIA_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_media[i].name,
+ sdp_media[i].strlen) == 0) {
+ mca_p->media = (sdp_media_e)i;
+ }
+ }
+ if (mca_p->media == SDP_MEDIA_UNSUPPORTED) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Media type unsupported (%s).",
+ sdp_p->debug_str, tmp);
+ }
+
+ /* Find the port token parameters, but don't process it until
+ * we determine the transport protocol as that determines what
+ * port number formats are valid.
+ */
+ ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No port specified in m= media line, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ port_ptr = port;
+ for (i=0; i < SDP_MAX_PORT_PARAMS; i++) {
+ if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result) == TRUE) {
+ num[i] = SDP_CHOOSE_PARAM;
+ } else {
+ num[i] = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
+ "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ break;
+ }
+ }
+ num_port_params++;
+ }
+
+ /* Find the transport protocol type. */
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No transport protocol type specified, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->transport = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ mca_p->transport = (sdp_transport_e)i;
+ break;
+ }
+ }
+
+ /* TODO(ehugg): Remove this next block when backward
+ compatibility with versions earlier than FF24
+ is no longer required. See Bug 886134 */
+#define DATACHANNEL_OLD_TRANSPORT "SCTP/DTLS"
+ if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
+ if (cpr_strncasecmp(tmp, DATACHANNEL_OLD_TRANSPORT,
+ strlen(DATACHANNEL_OLD_TRANSPORT)) == 0) {
+ mca_p->transport = SDP_TRANSPORT_DTLSSCTP;
+ }
+ }
+
+ if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
+ /* If we don't recognize or don't support the transport type,
+ * just store the first num as the port.
+ */
+ mca_p->port = num[0];
+ sdp_parse_error(sdp_p,
+ "%s Warning: Transport protocol type unsupported "
+ "(%s).", sdp_p->debug_str, tmp);
+ }
+
+ /* Check for each of the possible port formats according to the
+ * type of transport protocol specified.
+ */
+ valid_param = FALSE;
+ switch (num_port_params) {
+ case 1:
+ if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDP) ||
+ (mca_p->transport == SDP_TRANSPORT_TCP) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTL) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPSPRT) ||
+ (mca_p->transport == SDP_TRANSPORT_LOCAL) ||
+ (mca_p->transport == SDP_TRANSPORT_DTLSSCTP)) {
+ /* Port format is simply <port>. Make sure that either
+ * the choose param is allowed or that the choose value
+ * wasn't specified.
+ */
+ if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_PORTNUM]) ||
+ (num[0] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->port_format = SDP_PORT_NUM_ONLY;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
+ /* Port format is simply <vcci>, choose param is not allowed.
+ */
+ if (num[0] != SDP_CHOOSE_PARAM) {
+ mca_p->vcci = num[0];
+ mca_p->port_format = SDP_PORT_VCCI;
+ valid_param = TRUE;
+ }
+ } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is simply <port>, and choose param is allowed,
+ * according to AAL2 definitions.
+ */
+ mca_p->port = num[0];
+ mca_p->port_format = SDP_PORT_NUM_ONLY;
+ valid_param = TRUE;
+ }
+ break;
+ case 2:
+ if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVP) ||
+ (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVPF) ||
+ (mca_p->transport == SDP_TRANSPORT_UDP) ||
+ (mca_p->transport == SDP_TRANSPORT_LOCAL)) {
+ /* Port format is <port>/<num of ports>. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->num_ports = num[1];
+ mca_p->port_format = SDP_PORT_NUM_COUNT;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_UDPTL) {
+ /* Port format is <port>/<num of ports>. Make sure choose
+ * params were not specified. For UDPTL, only "1" may
+ * be specified for number of ports.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] == 1)) {
+ mca_p->port = num[0];
+ mca_p->num_ports = 1;
+ mca_p->port_format = SDP_PORT_NUM_COUNT;
+ valid_param = TRUE;
+ }
+ } else if (mca_p->transport == SDP_TRANSPORT_CES10) {
+ /* Port format is <vpi>/<vci>. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) {
+ mca_p->vpi = num[0];
+ mca_p->vci = num[1];
+ mca_p->port_format = SDP_PORT_VPI_VCI;
+ valid_param = TRUE;
+ }
+ } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is either <vcci>/<cid> or $/$. If one
+ * param is '$' the other must be also. The choose params
+ * are allowed by default and don't need to be allowed
+ * through the appl config.
+ */
+ if (((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM)) ||
+ ((num[0] == SDP_CHOOSE_PARAM) &&
+ (num[1] == SDP_CHOOSE_PARAM))) {
+ mca_p->vcci = num[0];
+ mca_p->cid = num[1];
+ mca_p->port_format = SDP_PORT_VCCI_CID;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ case 3:
+ if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
+ /* Port format is <port>/<vpi>/<vci>. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM) &&
+ (num[2] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->vpi = num[1];
+ mca_p->vci = num[2];
+ mca_p->port_format = SDP_PORT_NUM_VPI_VCI;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ case 4:
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ /* Port format is <port>/<vpi>/<vci>/<cid>. Make sure choose
+ * params were not specified.
+ */
+ if ((num[0] != SDP_CHOOSE_PARAM) &&
+ (num[1] != SDP_CHOOSE_PARAM) &&
+ (num[2] != SDP_CHOOSE_PARAM) &&
+ (num[3] != SDP_CHOOSE_PARAM)) {
+ mca_p->port = num[0];
+ mca_p->vpi = num[1];
+ mca_p->vci = num[2];
+ mca_p->cid = num[3];
+ mca_p->port_format = SDP_PORT_NUM_VPI_VCI_CID;
+ valid_param = TRUE;
+ }
+ }
+ break;
+ }
+ if (valid_param == FALSE) {
+ sdp_parse_error(sdp_p,
+ "%s Invalid port format (%s) specified for transport "
+ "protocol (%s), parse failed.", sdp_p->debug_str,
+ port, sdp_get_transport_name(mca_p->transport));
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(mca_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Find payload formats. AAL2 media lines allow multiple
+ * transport/profile types per line, so these are handled differently. */
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+
+ if (sdp_parse_multiple_profile_payload_types(sdp_p, mca_p, ptr) !=
+ SDP_SUCCESS) {
+ sdp_p->conf_p->num_invalid_param++;
+ SDP_FREE(mca_p);
+ return (SDP_INVALID_PARAMETER);
+ }
+ /* Parse DTLS/SCTP port */
+ } else if (mca_p->transport == SDP_TRANSPORT_DTLSSCTP) {
+ ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No sctp port specified in m= media line, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ port_ptr = port;
+
+ if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result)) {
+ sctp_port = SDP_CHOOSE_PARAM;
+ } else {
+ sctp_port = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
+ "/ \t", &result);
+ if (result != SDP_SUCCESS) {
+ sdp_parse_error(sdp_p,
+ "%s No sctp port specified in m= media line, "
+ "parse failed.", sdp_p->debug_str);
+ SDP_FREE(mca_p);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+ mca_p->sctpport = sctp_port;
+ }
+ } else {
+ /* Transport is a non-AAL2 type and not SCTP. Parse payloads
+ normally. */
+ sdp_parse_payload_types(sdp_p, mca_p, ptr);
+ }
+
+
+ /* Media line params are valid. Add it into the SDP. */
+ sdp_p->mca_count++;
+ if (sdp_p->mca_p == NULL) {
+ sdp_p->mca_p = mca_p;
+ } else {
+ for (next_mca_p = sdp_p->mca_p; next_mca_p->next_p != NULL;
+ next_mca_p = next_mca_p->next_p) {
+ ; // Empty For
+ }
+ next_mca_p->next_p = mca_p;
+ }
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+
+ SDP_PRINT("%s Parsed media type %s, ", sdp_p->debug_str,
+ sdp_get_media_name(mca_p->media));
+ switch (mca_p->port_format) {
+ case SDP_PORT_NUM_ONLY:
+ SDP_PRINT("Port num %d, ", mca_p->port);
+ break;
+
+ case SDP_PORT_NUM_COUNT:
+ SDP_PRINT("Port num %d, count %d, ",
+ mca_p->port, mca_p->num_ports);
+ break;
+ case SDP_PORT_VPI_VCI:
+ SDP_PRINT("VPI/VCI %d/%u, ", mca_p->vpi, mca_p->vci);
+ break;
+ case SDP_PORT_VCCI:
+ SDP_PRINT("VCCI %d, ", mca_p->vcci);
+ break;
+ case SDP_PORT_NUM_VPI_VCI:
+ SDP_PRINT("Port %d, VPI/VCI %d/%u, ", mca_p->port,
+ mca_p->vpi, mca_p->vci);
+ break;
+ case SDP_PORT_VCCI_CID:
+ SDP_PRINT("VCCI %d, CID %d, ", mca_p->vcci, mca_p->cid);
+ break;
+ case SDP_PORT_NUM_VPI_VCI_CID:
+ SDP_PRINT("Port %d, VPI/VCI %d/%u, CID %d, ", mca_p->port,
+ mca_p->vpi, mca_p->vci, mca_p->cid);
+ break;
+ default:
+ SDP_PRINT("Port format not valid, ");
+ break;
+ }
+
+ if ((mca_p->transport >= SDP_TRANSPORT_AAL2_ITU) &&
+ (mca_p->transport <= SDP_TRANSPORT_AAL2_CUSTOM)) {
+ for (i=0; i < mca_p->media_profiles_p->num_profiles; i++) {
+ SDP_PRINT("Profile %s, Num payloads %u ",
+ sdp_get_transport_name(mca_p->media_profiles_p->profile[i]),
+ (unsigned)mca_p->media_profiles_p->num_payloads[i]);
+ }
+ } else {
+ SDP_PRINT("Transport %s, Num payloads %u",
+ sdp_get_transport_name(mca_p->transport),
+ (unsigned)mca_p->num_payloads);
+ }
+ }
+ return (SDP_SUCCESS);
+}
+
+sdp_result_e sdp_build_media (sdp_t *sdp_p, uint16_t level, flex_string *fs)
+{
+ int i, j;
+ sdp_mca_t *mca_p;
+ tinybool invalid_params=FALSE;
+ sdp_media_profiles_t *profile_p;
+
+ /* Find the right media line */
+ mca_p = sdp_find_media_level(sdp_p, level);
+ if (mca_p == NULL) {
+ return (SDP_FAILURE);
+ }
+
+ /* Validate params for this media line */
+ if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
+ (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
+ (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
+ invalid_params = TRUE;
+ }
+
+ if (invalid_params == TRUE) {
+ CSFLogError(logTag, "%s Invalid params for m= media line, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ }
+
+ /* Build the media type */
+ flex_string_sprintf(fs, "m=%s ", sdp_get_media_name(mca_p->media));
+
+ /* Build the port based on the specified port format */
+ if (mca_p->port_format == SDP_PORT_NUM_ONLY) {
+ if (mca_p->port == SDP_CHOOSE_PARAM) {
+ flex_string_sprintf(fs, "$ ");
+ } else {
+ flex_string_sprintf(fs, "%u ", (unsigned)mca_p->port);
+ }
+ } else if (mca_p->port_format == SDP_PORT_NUM_COUNT) {
+ flex_string_sprintf(fs, "%u/%u ", (unsigned)mca_p->port,
+ (unsigned)mca_p->num_ports);
+ } else if (mca_p->port_format == SDP_PORT_VPI_VCI) {
+ flex_string_sprintf(fs, "%u/%u ",
+ (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
+ } else if (mca_p->port_format == SDP_PORT_VCCI) {
+ flex_string_sprintf(fs, "%u ", (unsigned)mca_p->vcci);
+ } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI) {
+ flex_string_sprintf(fs, "%u/%u/%u ", (unsigned)mca_p->port,
+ (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
+ } else if (mca_p->port_format == SDP_PORT_VCCI_CID) {
+ if ((mca_p->vcci == SDP_CHOOSE_PARAM) &&
+ (mca_p->cid == SDP_CHOOSE_PARAM)) {
+ flex_string_sprintf(fs, "$/$ ");
+ } else if ((mca_p->vcci == SDP_CHOOSE_PARAM) ||
+ (mca_p->cid == SDP_CHOOSE_PARAM)) {
+ /* If one is set but not the other, this is an error. */
+ CSFLogError(logTag, "%s Invalid params for m= port parameter, "
+ "build failed.", sdp_p->debug_str);
+ sdp_p->conf_p->num_invalid_param++;
+ return (SDP_INVALID_PARAMETER);
+ } else {
+ flex_string_sprintf(fs, "%u/%u ",
+ (unsigned)mca_p->vcci, (unsigned)mca_p->cid);
+ }
+ } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI_CID) {
+ flex_string_sprintf(fs, "%u/%u/%u/%u ", (unsigned)mca_p->port,
+ (unsigned)mca_p->vpi, (unsigned)mca_p->vci, (unsigned)mca_p->cid);
+ }
+
+ /* If the media line has AAL2 profiles, build them differently. */
+ if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
+ (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
+ profile_p = mca_p->media_profiles_p;
+ for (i=0; i < profile_p->num_profiles; i++) {
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(profile_p->profile[i]));
+
+ for (j=0; j < profile_p->num_payloads[i]; j++) {
+ flex_string_sprintf(fs, " %u",
+ (unsigned)profile_p->payload_type[i][j]);
+ }
+ flex_string_sprintf(fs, " ");
+ }
+ flex_string_sprintf(fs, "\n");
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+ }
+
+ /* Build the transport name */
+ flex_string_sprintf(fs, "%s",
+ sdp_get_transport_name(mca_p->transport));
+
+ if(mca_p->transport != SDP_TRANSPORT_DTLSSCTP) {
+
+ /* Build the format lists */
+ for (i=0; i < mca_p->num_payloads; i++) {
+ if (mca_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
+ flex_string_sprintf(fs, " %s",
+ sdp_get_payload_name((sdp_payload_e)mca_p->payload_type[i]));
+ } else {
+ flex_string_sprintf(fs, " %u", (unsigned)mca_p->payload_type[i]);
+ }
+ }
+ } else {
+ /* Add port to SDP if transport is DTLS/SCTP */
+ flex_string_sprintf(fs, " %u", (unsigned)mca_p->sctpport);
+ }
+
+ flex_string_sprintf(fs, "\r\n");
+
+ if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
+ SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
+ }
+ return (SDP_SUCCESS);
+}
+
+
+/* Function: sdp_parse_payload_types
+ * Description: Parse a list of payload types. The list may be part of
+ * a media line or part of a capability line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * mca_p The mca structure the payload types should be
+ * added to.
+ * ptr The pointer to the list of payloads.
+ * Returns: Nothing.
+ */
+void sdp_parse_payload_types (sdp_t *sdp_p, sdp_mca_t *mca_p, const char *ptr)
+{
+ uint16_t i;
+ uint16_t num_payloads;
+ sdp_result_e result;
+ tinybool valid_payload;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *tmp2;
+
+ for (num_payloads = 0; (num_payloads < SDP_MAX_PAYLOAD_TYPES); ) {
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ /* If there are no more payload types, we're finished */
+ break;
+ }
+ mca_p->payload_type[num_payloads] = (uint16_t)sdp_getnextnumtok(tmp,
+ (const char **)&tmp2,
+ " \t", &result);
+ if (result == SDP_SUCCESS) {
+ if ((mca_p->media == SDP_MEDIA_IMAGE) &&
+ (mca_p->transport == SDP_TRANSPORT_UDPTL)) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Numeric payload type not "
+ "valid for media %s with transport %s.",
+ sdp_p->debug_str,
+ sdp_get_media_name(mca_p->media),
+ sdp_get_transport_name(mca_p->transport));
+ } else {
+ mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_NUMERIC;
+ mca_p->num_payloads++;
+ num_payloads++;
+ }
+ continue;
+ }
+
+ valid_payload = FALSE;
+ for (i=0; i < SDP_MAX_STRING_PAYLOAD_TYPES; i++) {
+ if (cpr_strncasecmp(tmp, sdp_payload[i].name,
+ sdp_payload[i].strlen) == 0) {
+ valid_payload = TRUE;
+ break;
+ }
+ }
+ if (valid_payload == TRUE) {
+ /* We recognized the payload type. Make sure it
+ * is valid for this media line. */
+ valid_payload = FALSE;
+ if ((mca_p->media == SDP_MEDIA_IMAGE) &&
+ (mca_p->transport == SDP_TRANSPORT_UDPTL) &&
+ (i == SDP_PAYLOAD_T38)) {
+ valid_payload = TRUE;
+ } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
+ (mca_p->transport == SDP_TRANSPORT_UDP) &&
+ (i == SDP_PAYLOAD_XTMR)) {
+ valid_payload = TRUE;
+ } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
+ (mca_p->transport == SDP_TRANSPORT_TCP) &&
+ (i == SDP_PAYLOAD_T120)) {
+ valid_payload = TRUE;
+ }
+
+ if (valid_payload == TRUE) {
+ mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_ENUM;
+ mca_p->payload_type[num_payloads] = i;
+ mca_p->num_payloads++;
+ num_payloads++;
+ } else {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Payload type %s not valid for "
+ "media %s with transport %s.",
+ sdp_p->debug_str,
+ sdp_get_payload_name((sdp_payload_e)i),
+ sdp_get_media_name(mca_p->media),
+ sdp_get_transport_name(mca_p->transport));
+ }
+ } else {
+ /* Payload type wasn't recognized. */
+ sdp_parse_error(sdp_p,
+ "%s Warning: Payload type "
+ "unsupported (%s).", sdp_p->debug_str, tmp);
+ }
+ }
+ if (mca_p->num_payloads == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No payload types specified.",
+ sdp_p->debug_str);
+ }
+}
+
+
+/* Function: sdp_parse_multiple_profile_payload_types
+ * Description: Parse a list of payload types. The list may be part of
+ * a media line or part of a capability line.
+ * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
+ * mca_p The mca structure the payload types should be
+ * added to.
+ * ptr The pointer to the list of payloads.
+ * Returns: Nothing.
+ */
+sdp_result_e sdp_parse_multiple_profile_payload_types (sdp_t *sdp_p,
+ sdp_mca_t *mca_p,
+ const char *ptr)
+{
+ uint16_t i;
+ uint16_t prof;
+ uint16_t payload;
+ sdp_result_e result;
+ sdp_media_profiles_t *profile_p;
+ char tmp[SDP_MAX_STRING_LEN];
+ char *tmp2;
+
+ /* If the transport type is any of the AAL2 formats, then we
+ * need to look for multiple AAL2 profiles and their associated
+ * payload lists. */
+ mca_p->media_profiles_p = (sdp_media_profiles_t *) \
+ SDP_MALLOC(sizeof(sdp_media_profiles_t));
+ if (mca_p->media_profiles_p == NULL) {
+ sdp_p->conf_p->num_no_resource++;
+ SDP_FREE(mca_p);
+ return (SDP_NO_RESOURCE);
+ }
+ profile_p = mca_p->media_profiles_p;
+ /* Set the first profile to the one already detected. */
+ profile_p->num_profiles = 1;
+ prof = 0;
+ payload = 0;
+ profile_p->profile[prof] = mca_p->transport;
+ profile_p->num_payloads[prof] = 0;
+
+ /* Now find the payload type lists and any other profile types */
+ while (TRUE) {
+ ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
+ if (result != SDP_SUCCESS) {
+ /* If there are no more payload types, we're finished */
+ break;
+ }
+
+ /* See if the next token is a new profile type. */
+ if (prof < SDP_MAX_PROFILES) {
+ profile_p->profile[prof+1] = SDP_TRANSPORT_UNSUPPORTED;
+ for (i=SDP_TRANSPORT_AAL2_ITU;
+ i <= SDP_TRANSPORT_AAL2_CUSTOM; i++) {
+ if (cpr_strncasecmp(tmp, sdp_transport[i].name,
+ sdp_transport[i].strlen) == 0) {
+ profile_p->profile[prof+1] = (sdp_transport_e)i;
+ break;
+ }
+ }
+ /* If we recognized the profile type, start looking for the
+ * next payload list. */
+ if (profile_p->profile[prof+1] != SDP_TRANSPORT_UNSUPPORTED) {
+ /* Now reset the payload counter for the next profile type. */
+ payload = 0;
+ prof++;
+ profile_p->num_profiles++;
+ if (prof < SDP_MAX_PROFILES) {
+ profile_p->num_payloads[prof] = 0;
+ }
+ continue;
+ }
+ }
+
+ /* This token must be a payload type. Make sure there aren't
+ * too many payload types. */
+ if (payload >= SDP_MAX_PAYLOAD_TYPES) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: Too many payload types "
+ "found, truncating.", sdp_p->debug_str);
+ continue;
+ }
+
+ /* See if the payload type is numeric. */
+ if (prof < SDP_MAX_PROFILES && payload < SDP_MAX_PAYLOAD_TYPES) {
+ profile_p->payload_type[prof][payload] = (uint16_t)sdp_getnextnumtok(tmp,
+ (const char **)&tmp2,
+ " \t", &result);
+ if (result == SDP_SUCCESS) {
+ profile_p->payload_indicator[prof][payload] = SDP_PAYLOAD_NUMERIC;
+ profile_p->num_payloads[prof]++;
+ payload++;
+ continue;
+ }
+ }
+
+ /* No string payload types are currently valid for the AAL2
+ * transport types. This support can be added when needed. */
+ sdp_parse_error(sdp_p,
+ "%s Warning: Unsupported payload type "
+ "found (%s).", sdp_p->debug_str, tmp);
+ }
+ for (i=0; i < profile_p->num_profiles; i++) {
+ /* Make sure we have payloads for each profile type. */
+ if (profile_p->num_payloads[i] == 0) {
+ sdp_parse_error(sdp_p,
+ "%s Warning: No payload types specified "
+ "for AAL2 profile %s.", sdp_p->debug_str,
+ sdp_get_transport_name(profile_p->profile[i]));
+ }
+ }
+ return (SDP_SUCCESS);
+}
diff --git a/media/webrtc/signaling/src/sdp/sipcc/sdp_utils.c b/media/webrtc/signaling/src/sdp/sipcc/sdp_utils.c
new file mode 100644
index 000000000..a02035c72
--- /dev/null
+++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_utils.c
@@ -0,0 +1,781 @@
+/* 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/. */
+
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+#include "sdp_os_defs.h"
+#include "sdp.h"
+#include "sdp_private.h"
+
+#include "CSFLog.h"
+
+#define MKI_BUF_LEN 4
+
+static const char* logTag = "sdp_utils";
+
+sdp_mca_t *sdp_alloc_mca (uint32_t line) {
+ sdp_mca_t *mca_p;
+
+ /* Allocate resource for new media stream. */
+ mca_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t));
+ if (mca_p == NULL) {
+ return (NULL);
+ }
+ /* Initialize mca structure */
+ mca_p->media = SDP_MEDIA_INVALID;
+ mca_p->conn.nettype = SDP_NT_INVALID;
+ mca_p->conn.addrtype = SDP_AT_INVALID;
+ mca_p->conn.conn_addr[0] = '\0';
+ mca_p->conn.is_multicast = FALSE;
+ mca_p->conn.ttl = 0;
+ mca_p->conn.num_of_addresses = 0;
+ mca_p->transport = SDP_TRANSPORT_INVALID;
+ mca_p->port = SDP_INVALID_VALUE;
+ mca_p->num_ports = SDP_INVALID_VALUE;
+ mca_p->vpi = SDP_INVALID_VALUE;
+ mca_p->vci = 0;
+ mca_p->vcci = SDP_INVALID_VALUE;
+ mca_p->cid = SDP_INVALID_VALUE;
+ mca_p->num_payloads = 0;
+ mca_p->sessinfo_found = FALSE;
+ mca_p->encrypt.encrypt_type = SDP_ENCRYPT_INVALID;
+ mca_p->media_attrs_p = NULL;
+ mca_p->next_p = NULL;
+ mca_p->mid = 0;
+ mca_p->bw.bw_data_count = 0;
+ mca_p->bw.bw_data_list = NULL;
+ mca_p->line_number = line;
+
+ return (mca_p);
+}
+
+/*
+ * next_token
+ *
+ * copy token param with chars from str until null, cr, lf, or one of the delimiters is found.
+ * delimiters at the beginning will be skipped.
+ * The pointer *string_of_tokens is moved forward to the next token on sucess.
+ *
+ */
+static sdp_result_e next_token(const char **string_of_tokens, char *token, unsigned token_max_len, const char *delim)
+{
+ int flag2moveon = 0;
+ const char *str;
+ const char *token_end;
+ const char *next_delim;
+
+ if (!string_of_tokens || !*string_of_tokens || !token || !delim) {
+ return SDP_FAILURE;
+ }
+
+ str = *string_of_tokens;
+ token_end = token + token_max_len - 1;
+
+ /* Locate front of token, skipping any delimiters */
+ for ( ; ((*str != '\0') && (*str != '\n') && (*str != '\r')); str++) {
+ flag2moveon = 1; /* Default to move on unless we find a delimiter */
+ for (next_delim=delim; *next_delim; next_delim++) {
+ if (*str == *next_delim) {
+ flag2moveon = 0;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break; /* We're at the beginning of the token */
+ }
+ }
+
+ /* Make sure there's really a token present. */
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ return SDP_EMPTY_TOKEN;
+ }
+
+ /* Now locate end of token */
+ flag2moveon = 0;
+
+ while ((token < token_end) &&
+ (*str != '\0') && (*str != '\n') && (*str != '\r')) {
+ for (next_delim=delim; *next_delim; next_delim++) {
+ if (*str == *next_delim) {
+ flag2moveon = 1;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break;
+ } else {
+ *token++ = *str++;
+ }
+ }
+
+ /* mark end of token */
+ *token = '\0';
+
+ /* set the string of tokens to the next token */
+ *string_of_tokens = str;
+
+ return SDP_SUCCESS;
+}
+
+/*
+ * verify_sdescriptions_mki
+ *
+ * Verifies the syntax of the MKI parameter.
+ *
+ * mki = mki-value ":" mki-length
+ * mki-value = 1*DIGIT
+ * mki-length = 1*3DIGIT ; range 1..128
+ *
+ * Inputs:
+ * buf - ptr to start of MKI string assumes NULL
+ * terminated string
+ * mkiValue - buffer to store the MKI value, assumes calling
+ * function has provided memory for this.
+ * mkiLen - integer to store the MKI length
+ *
+ * Outputs:
+ * Returns TRUE if syntax is correct and stores the
+ * MKI value in mkiVal and stores the length in mkiLen.
+ * Returns FALSE otherwise.
+ */
+
+tinybool
+verify_sdescriptions_mki (char *buf, char *mkiVal, uint16_t *mkiLen)
+{
+
+ char *ptr,
+ mkiValBuf[SDP_SRTP_MAX_MKI_SIZE_BYTES],
+ mkiLenBuf[MKI_BUF_LEN];
+ int idx = 0;
+ unsigned long strtoul_result;
+ char *strtoul_end;
+
+ ptr = buf;
+ /* MKI must begin with a digit */
+ if (!ptr || (!isdigit((int) *ptr))) {
+ return FALSE;
+ }
+
+ /* scan until we reach a non-digit or colon */
+ while (*ptr) {
+ if (*ptr == ':') {
+ /* terminate the MKI value */
+ mkiValBuf[idx] = 0;
+ ptr++;
+ break;
+ } else if ((isdigit((int) *ptr) && (idx < SDP_SRTP_MAX_MKI_SIZE_BYTES-1))) {
+ mkiValBuf[idx++] = *ptr;
+ } else {
+ return FALSE;
+ }
+
+ ptr++;
+ }
+
+ /* there has to be a mki length */
+ if (*ptr == 0) {
+ return FALSE;
+ }
+
+ idx = 0;
+
+ /* verify the mki length (max 3 digits) */
+ while (*ptr) {
+ if (isdigit((int) *ptr) && (idx < 3)) {
+ mkiLenBuf[idx++] = *ptr;
+ } else {
+ return FALSE;
+ }
+
+ ptr++;
+ }
+
+ mkiLenBuf[idx] = 0;
+
+ errno = 0;
+ strtoul_result = strtoul(mkiLenBuf, &strtoul_end, 10);
+
+ /* mki len must be between 1..128 */
+ if (errno || mkiLenBuf == strtoul_end || strtoul_result < 1 || strtoul_result > 128) {
+ *mkiLen = 0;
+ return FALSE;
+ }
+
+ *mkiLen = (uint16_t) strtoul_result;
+ sstrncpy(mkiVal, mkiValBuf, MKI_BUF_LEN);
+
+ return TRUE;
+}
+
+/*
+ * verify_srtp_lifetime
+ *
+ * Verifies the Lifetime parameter syntax.
+ *
+ * lifetime = ["2^"] 1*(DIGIT)
+ *
+ * Inputs:
+ * buf - pointer to start of lifetime string. Assumes string is
+ * NULL terminated.
+ * Outputs:
+ * Returns TRUE if syntax is correct. Returns FALSE otherwise.
+ */
+
+tinybool
+verify_sdescriptions_lifetime (char *buf)
+{
+
+ char *ptr;
+ tinybool tokenFound = FALSE;
+
+ ptr = buf;
+ if (!ptr || *ptr == 0) {
+ return FALSE;
+ }
+
+ while (*ptr) {
+ if (*ptr == '^') {
+ if (tokenFound) {
+ /* make sure we don't have multiple ^ */
+ return FALSE;
+ } else {
+ tokenFound = TRUE;
+ /* Lifetime is in power of 2 format, make sure first and second
+ * chars are 2^
+ */
+
+ if (buf[0] != '2' || buf[1] != '^') {
+ return FALSE;
+ }
+ }
+ } else if (!isdigit((int) *ptr)) {
+ return FALSE;
+ }
+
+ ptr++;
+
+ }
+
+ /* Make sure if the format is 2^ that there is a number after the ^. */
+ if (tokenFound) {
+ if (strlen(buf) <= 2) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * sdp_validate_maxprate
+ *
+ * This function validates that the string passed in is of the form:
+ * packet-rate = 1*DIGIT ["." 1*DIGIT]
+ */
+tinybool
+sdp_validate_maxprate(const char *string_parm)
+{
+ tinybool retval = FALSE;
+
+ if (string_parm && (*string_parm)) {
+ while (isdigit((int)*string_parm)) {
+ string_parm++;
+ }
+
+ if (*string_parm == '.') {
+ string_parm++;
+ while (isdigit((int)*string_parm)) {
+ string_parm++;
+ }
+ }
+
+ if (*string_parm == '\0') {
+ retval = TRUE;
+ } else {
+ retval = FALSE;
+ }
+ }
+
+ return retval;
+}
+
+char *sdp_findchar (const char *ptr, char *char_list)
+{
+ int i;
+
+ for (;*ptr != '\0'; ptr++) {
+ for (i=0; char_list[i] != '\0'; i++) {
+ if (*ptr == char_list[i]) {
+ return ((char *)ptr);
+ }
+ }
+ }
+ return ((char *)ptr);
+}
+
+/* Locate the next token in a line. The delim characters are passed in
+ * as a param. The token also will not go past a new line char or the
+ * end of the string. Skip any delimiters before the token.
+ */
+const char *sdp_getnextstrtok (const char *str, char *tokenstr, unsigned tokenstr_len,
+ const char *delim, sdp_result_e *result)
+{
+ const char *token_list = str;
+
+ if (!str || !tokenstr || !delim || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return str;
+ }
+
+ *result = next_token(&token_list, tokenstr, tokenstr_len, delim);
+
+ return token_list;
+}
+
+
+
+/* Locate the next null ("-") or numeric token in a string. The delim
+ * characters are passed in as a param. The token also will not go past
+ * a new line char or the end of the string. Skip any delimiters before
+ * the token.
+ */
+uint32_t sdp_getnextnumtok_or_null (const char *str, const char **str_end,
+ const char *delim, tinybool *null_ind,
+ sdp_result_e *result)
+{
+ const char *token_list = str;
+ char temp_token[SDP_MAX_STRING_LEN];
+ char *strtoul_end;
+ unsigned long numval;
+
+ if (null_ind) {
+ *null_ind = FALSE;
+ }
+
+ if (!str || !str_end || !delim || !null_ind || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return 0;
+ }
+
+ *result = next_token(&token_list, temp_token, sizeof(temp_token), delim);
+
+ if (*result != SDP_SUCCESS) {
+ return 0;
+ }
+
+ /* First see if its the null char ("-") */
+ if (temp_token[0] == '-') {
+ *null_ind = TRUE;
+ *result = SDP_SUCCESS;
+ *str_end = str;
+ return 0;
+ }
+
+ errno = 0;
+ numval = strtoul(temp_token, &strtoul_end, 10);
+
+ if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
+ *result = SDP_FAILURE;
+ return 0;
+ }
+
+ *result = SDP_SUCCESS;
+ *str_end = token_list;
+ return (uint32_t) numval;
+}
+
+
+/* Locate the next numeric token in a string. The delim characters are
+ * passed in as a param. The token also will not go past a new line char
+ * or the end of the string. Skip any delimiters before the token.
+ */
+uint32_t sdp_getnextnumtok (const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result)
+{
+ const char *token_list = str;
+ char temp_token[SDP_MAX_STRING_LEN];
+ char *strtoul_end;
+ unsigned long numval;
+
+ if (!str || !str_end || !delim || !result) {
+ if (result) {
+ *result = SDP_FAILURE;
+ }
+ return 0;
+ }
+
+ *result = next_token(&token_list, temp_token, sizeof(temp_token), delim);
+
+ if (*result != SDP_SUCCESS) {
+ return 0;
+ }
+
+ errno = 0;
+ numval = strtoul(temp_token, &strtoul_end, 10);
+
+ if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
+ *result = SDP_FAILURE;
+ return 0;
+ }
+
+ *result = SDP_SUCCESS;
+ *str_end = token_list;
+ return (uint32_t) numval;
+}
+
+
+/* See if the next token in a string is the choose character. The delim
+ * characters are passed in as a param. The check also will not go past
+ * a new line char or the end of the string. Skip any delimiters before
+ * the token.
+ */
+tinybool sdp_getchoosetok (const char *str, const char **str_end,
+ const char *delim, sdp_result_e *result)
+{
+ const char *b;
+ int flag2moveon;
+
+ if ((str == NULL) || (str_end == NULL)) {
+ *result = SDP_FAILURE;
+ return(FALSE);
+ }
+
+ /* Locate front of token, skipping any delimiters */
+ for ( ; ((*str != '\0') && (*str != '\n') && (*str != '\r')); str++) {
+ flag2moveon = 1; /* Default to move on unless we find a delimiter */
+ for (b=delim; *b; b++) {
+ if (*str == *b) {
+ flag2moveon = 0;
+ break;
+ }
+ }
+ if( flag2moveon ) {
+ break; /* We're at the beginning of the token */
+ }
+ }
+
+ /* Make sure there's really a token present. */
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ *result = SDP_FAILURE;
+ *str_end = (char *)str;
+ return(FALSE);
+ }
+
+ /* See if the token is '$' followed by a delimiter char or end of str. */
+ if (*str == '$') {
+ str++;
+ if ((*str == '\0') || (*str == '\n') || (*str == '\r')) {
+ *result = SDP_SUCCESS;
+ /* skip the choose char in the string. */
+ *str_end = (char *)(str+1);
+ return(TRUE);
+ }
+ for (b=delim; *b; b++) {
+ if (*str == *b) {
+ *result = SDP_SUCCESS;
+ /* skip the choose char in the string. */
+ *str_end = (char *)(str+1);
+ return(TRUE);
+ }
+ }
+ }
+
+ /* If the token was not '$' followed by a delim, token is not choose */
+ *result = SDP_SUCCESS;
+ *str_end = (char *)str;
+ return(FALSE);
+
+}
+
+/*
+ * SDP Crypto Utility Functions.
+ *
+ * First a few common definitions.
+ */
+
+/*
+ * Constants
+ *
+ * crypto_string = The string used to identify the start of sensative
+ * crypto data.
+ *
+ * inline_string = The string used to identify the start of key/salt
+ * crypto data.
+ *
+ * star_string = The string used to overwrite sensative data.
+ *
+ * '*_strlen' = The length of '*_string' in bytes (not including '\0')
+ */
+static const char crypto_string[] = "X-crypto:";
+static const int crypto_strlen = sizeof(crypto_string) - 1;
+static const char inline_string[] = "inline:";
+static const int inline_strlen = sizeof(inline_string) - 1;
+/* 40 characters is the current maximum for a Base64 encoded key/salt */
+static const char star_string[] = "****************************************";
+static const int star_strlen = sizeof(star_string) - 1;
+
+/*
+ * MIN_CRYPTO_STRING_SIZE_BYTES = This value defines the minimum
+ * size of a string that could contain a key/salt. This value
+ * is used to skip out of parsing when there is no reasonable
+ * assumption that sensative data will be found. The general
+ * format of a SRTP Key Salt in SDP looks like:
+ *
+ * X-crypto:<crypto_suite_name> inline:<master_key_salt>||
+ *
+ * if <crypto_suite_name> and <master_key_salt> is at least
+ * one character and one space is used before the "inline:",
+ * then this translates to a size of (aligned by collumn from
+ * the format shown above):
+ *
+ * 9+ 1+ 1+7+ 1+ 2 = 21
+ *
+ */
+#define MIN_CRYPTO_STRING_SIZE_BYTES 21
+
+/*
+ * Utility macros
+ *
+ * CHAR_IS_WHITESPACE = macro to determine if the passed _test_char
+ * is whitespace.
+ *
+ * SKIP_WHITESPACE = Macro to advance _cptr to the next non-whitespace
+ * character. _cptr will not be advanced past _max_cptr.
+ *
+ * FIND_WHITESPACE = Macro to advance _cptr until whitespace is found.
+ * _cptr will not be advanced past _max_cptr.
+ */
+#define CHAR_IS_WHITESPACE(_test_char) \
+ ((((_test_char)==' ')||((_test_char)=='\t'))?1:0)
+
+#define SKIP_WHITESPACE(_cptr, _max_cptr) \
+ while ((_cptr)<=(_max_cptr)) { \
+ if (!CHAR_IS_WHITESPACE(*(_cptr))) break; \
+ (_cptr)++; \
+ }
+
+#define FIND_WHITESPACE(_cptr, _max_cptr) \
+ while ((_cptr)<=(_max_cptr)) { \
+ if (CHAR_IS_WHITESPACE(*(_cptr))) break; \
+ (_cptr)++; \
+ }
+
+/* Function: sdp_crypto_debug
+ * Description: Check the passed buffer for sensitive data that should
+ * not be output (such as SRTP Master Key/Salt) and output
+ * the buffer as debug. Sensitive data will be replaced
+ * with the '*' character(s). This function may be used
+ * to display very large buffers so this function ensures
+ * that buginf is not overloaded.
+ * Parameters: buffer pointer to the message buffer to filter.
+ * length_bytes size of message buffer in bytes.
+ * Returns: Nothing.
+ */
+void sdp_crypto_debug (char *buffer, ulong length_bytes)
+{
+ char *current, *start;
+ char *last = buffer + length_bytes;
+ int result;
+
+ /*
+ * For SRTP Master Key/Salt has the form:
+ * X-crypto:<crypto_suite_name> inline:<master_key_salt>||
+ * Where <master_key_salt> is the data to elide (filter).
+ */
+ for (start=current=buffer;
+ current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
+ current++) {
+ if ((*current == 'x') || (*current == 'X')) {
+ result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
+ if (!result) {
+ current += crypto_strlen;
+ if (current > last) break;
+
+ /* Skip over crypto suite name */
+ FIND_WHITESPACE(current, last);
+
+ /* Skip over whitespace */
+ SKIP_WHITESPACE(current, last);
+
+ /* identify inline keyword */
+ result = cpr_strncasecmp(current, inline_string, inline_strlen);
+ if (!result) {
+ int star_count = 0;
+
+ current += inline_strlen;
+ if (current > last) break;
+
+ sdp_dump_buffer(start, current - start);
+
+ /* Hide sensitive key/salt data */
+ while (current<=last) {
+ if (*current == '|' || *current == '\n') {
+ /* Done, print the stars */
+ while (star_count > star_strlen) {
+ /*
+ * This code is only for the case where
+ * too much base64 data was supplied
+ */
+ sdp_dump_buffer((char*)star_string, star_strlen);
+ star_count -= star_strlen;
+ }
+ sdp_dump_buffer((char*)star_string, star_count);
+ break;
+ } else {
+ star_count++;
+ current++;
+ }
+ }
+ /* Update start pointer */
+ start=current;
+ }
+ }
+ }
+ }
+
+ if (last > start) {
+ /* Display remainder of buffer */
+ sdp_dump_buffer(start, last - start);
+ }
+}
+
+/*
+ * sdp_debug_msg_filter
+ *
+ * DESCRIPTION
+ * Check the passed message buffer for sensitive data that should
+ * not be output (such as SRTP Master Key/Salt). Sensitive data
+ * will be replaced with the '*' character(s).
+ *
+ * PARAMETERS
+ * buffer: pointer to the message buffer to filter.
+ *
+ * length_bytes: size of message buffer in bytes.
+ *
+ * RETURN VALUE
+ * The buffer modified.
+ */
+char * sdp_debug_msg_filter (char *buffer, ulong length_bytes)
+{
+ char *current;
+ char *last = buffer + length_bytes;
+ int result;
+
+ SDP_PRINT("\n%s:%d: Eliding sensitive data from debug output",
+ __FILE__, __LINE__);
+ /*
+ * For SRTP Master Key/Salt has the form:
+ * X-crypto:<crypto_suite_name> inline:<master_key_salt>||
+ * Where <master_key_salt> is the data to elide (filter).
+ */
+ for (current=buffer;
+ current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
+ current++) {
+ if ((*current == 'x') || (*current == 'X')) {
+ result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
+ if (!result) {
+ current += crypto_strlen;
+ if (current > last) break;
+
+ /* Skip over crypto suite name */
+ FIND_WHITESPACE(current, last);
+
+ /* Skip over whitespace */
+ SKIP_WHITESPACE(current, last);
+
+ /* identify inline keyword */
+ result = cpr_strncasecmp(current, inline_string, inline_strlen);
+ if (!result) {
+ current += inline_strlen;
+ if (current > last) break;
+
+ /* Hide sensitive key/salt data */
+ while (current<=last) {
+ if (*current == '|' || *current == '\n') {
+ /* Done */
+ break;
+ } else {
+ *current = '*';
+ current++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return buffer;
+}
+
+
+/* Function: sdp_checkrange
+ * Description: This checks the range of a ulong value to make sure its
+ * within the range of 0 and 4Gig. stroul cannot be used since
+ * for values greater greater than 4G, stroul will either wrap
+ * around or return ULONG_MAX.
+ * Parameters: sdp_p Pointer to the sdp structure
+ * num The number to check the range for
+ * u_val This variable get populated with the ulong value
+ * if the number is within the range.
+ * Returns: tinybool - returns TRUE if the number passed is within the
+ * range, FALSE otherwise
+ */
+tinybool sdp_checkrange (sdp_t *sdp_p, char *num, ulong *u_val)
+{
+ ulong l_val;
+ char *endP = NULL;
+ *u_val = 0;
+
+ if (!num || !*num) {
+ return FALSE;
+ }
+
+ if (*num == '-') {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value is a negative number: %s",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+
+ l_val = strtoul(num, &endP, 10);
+ if (*endP == '\0') {
+
+ if (l_val > 4294967295UL) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+
+ if (l_val == 4294967295UL) {
+ /*
+ * On certain platforms where ULONG_MAX is equivalent to
+ * 4294967295, strtoul will return ULONG_MAX even if the the
+ * value of the string is greater than 4294967295. To detect
+ * that scenario we make an explicit check here.
+ */
+ if (strcmp("4294967295", num)) {
+ if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
+ CSFLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295",
+ sdp_p->debug_str, num);
+ }
+ return FALSE;
+ }
+ }
+ }
+ *u_val = l_val;
+ return TRUE;
+}
+
+#undef CHAR_IS_WHITESPACE
+#undef SKIP_WHITESPACE
+#undef FIND_WHITESPACE