aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2022-09-27 22:27:20 +0200
committerLinus Jahn <lnj@kaidan.im>2022-10-01 19:50:31 +0200
commit1814f67c9a41eb750a56fdccd28843b53be17b0d (patch)
tree6b224b53f6fae15609752c4d30c1eb3b155b5efe /src/base
parent58646ad17d331f980fa1e03e3831fadea847c2b2 (diff)
downloadqxmpp-1814f67c9a41eb750a56fdccd28843b53be17b0d.tar.gz
Implement XEP-0294: Jingle RTP Header Extensions Negotiation stanzas
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppConstants.cpp2
-rw-r--r--src/base/QXmppConstants_p.h2
-rw-r--r--src/base/QXmppJingleIq.cpp263
-rw-r--r--src/base/QXmppJingleIq.h46
4 files changed, 312 insertions, 1 deletions
diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp
index a98e4754..1729d226 100644
--- a/src/base/QXmppConstants.cpp
+++ b/src/base/QXmppConstants.cpp
@@ -135,6 +135,8 @@ const char *ns_muji = "urn:xmpp:jingle:muji:0";
const char *ns_carbons = "urn:xmpp:carbons:2";
// XEP-0293: Jingle RTP Feedback Negotiation
const char *ns_jingle_rtp_feedback_negotiation = "urn:xmpp:jingle:apps:rtp:rtcp-fb:0";
+// XEP-0294: Jingle RTP Header Extensions Negotiation
+const char *ns_jingle_rtp_header_extensions_negotiation = "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0";
// XEP-0297: Stanza Forwarding
const char *ns_forwarding = "urn:xmpp:forward:0";
// XEP-0300: Use of Cryptographic Hash Functions in XMPP
diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h
index 8db12563..1f067b2b 100644
--- a/src/base/QXmppConstants_p.h
+++ b/src/base/QXmppConstants_p.h
@@ -147,6 +147,8 @@ extern const char *ns_muji;
extern const char *ns_carbons;
// XEP-0293: Jingle RTP Feedback Negotiation
extern const char *ns_jingle_rtp_feedback_negotiation;
+// XEP-0294: Jingle RTP Header Extensions Negotiation
+extern const char *ns_jingle_rtp_header_extensions_negotiation;
// XEP-0297: Stanza Forwarding
extern const char *ns_forwarding;
// XEP-0300: Use of Cryptographic Hash Functions in XMPP
diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp
index c6ae9ede..ff92993e 100644
--- a/src/base/QXmppJingleIq.cpp
+++ b/src/base/QXmppJingleIq.cpp
@@ -57,6 +57,12 @@ static const char *jingle_reasons[] = {
"unsupported-transports",
};
+static const QStringList JINGLE_RTP_HEADER_EXTENSIONS_SENDERS = {
+ QStringLiteral("both"),
+ QStringLiteral("initiator"),
+ QStringLiteral("responder")
+};
+
static QString formatFingerprint(const QByteArray &digest)
{
QString fingerprint;
@@ -136,7 +142,8 @@ static void parseSdpParameters(const QDomElement &parent, QVector<QXmppSdpParame
}
// Serializes the SDP parameters.
-static void sdpParametersToXml(QXmlStreamWriter *writer, const QVector<QXmppSdpParameter> &parameters) {
+static void sdpParametersToXml(QXmlStreamWriter *writer, const QVector<QXmppSdpParameter> &parameters)
+{
for (const auto &parameter : parameters) {
parameter.toXml(writer);
}
@@ -173,6 +180,37 @@ static void jingleRtpFeedbackNegotiationElementsToXml(QXmlStreamWriter *writer,
}
}
+// Parses all found RTP Header Extensions Negotiation elements inside of parent into properties and
+// isRtpHeaderExtensionMixingAllowed.
+static void parseJingleRtpHeaderExtensionsNegotiationElements(const QDomElement &parent, QVector<QXmppJingleRtpHeaderExtensionProperty> &properties, bool &isRtpHeaderExtensionMixingAllowed)
+{
+ for (auto child = parent.firstChildElement();
+ !child.isNull();
+ child = child.nextSiblingElement()) {
+ if (QXmppJingleRtpHeaderExtensionProperty::isJingleRtpHeaderExtensionProperty(child)) {
+ QXmppJingleRtpHeaderExtensionProperty property;
+ property.parse(child);
+ properties.append(property);
+ } else if (child.tagName() == QStringLiteral("extmap-allow-mixed") && child.namespaceURI() == ns_jingle_rtp_header_extensions_negotiation) {
+ isRtpHeaderExtensionMixingAllowed = true;
+ }
+ }
+}
+
+// Serializes the RTP header extension properties and isRtpHeaderExtensionMixingAllowed.
+static void jingleRtpHeaderExtensionsNegotiationElementsToXml(QXmlStreamWriter *writer, const QVector<QXmppJingleRtpHeaderExtensionProperty> &properties, bool isRtpHeaderExtensionMixingAllowed)
+{
+ for (const auto &property : properties) {
+ property.toXml(writer);
+ }
+
+ if (isRtpHeaderExtensionMixingAllowed) {
+ writer->writeStartElement(QStringLiteral("extmap-allow-mixed"));
+ writer->writeDefaultNamespace(ns_jingle_rtp_header_extensions_negotiation);
+ writer->writeEndElement();
+ }
+}
+
class QXmppJingleIqContentPrivate : public QSharedData
{
public:
@@ -202,6 +240,10 @@ public:
// XEP-0293: Jingle RTP Feedback Negotiation
QVector<QXmppJingleRtpFeedbackProperty> rtpFeedbackProperties;
QVector<QXmppJingleRtpFeedbackInterval> rtpFeedbackIntervals;
+
+ // XEP-0294: Jingle RTP Header Extensions Negotiation
+ QVector<QXmppJingleRtpHeaderExtensionProperty> rtpHeaderExtensionProperties;
+ bool isRtpHeaderExtensionMixingAllowed = false;
};
QXmppJingleIqContentPrivate::QXmppJingleIqContentPrivate()
@@ -481,6 +523,58 @@ void QXmppJingleIq::Content::setRtpFeedbackIntervals(const QVector<QXmppJingleRt
}
///
+/// Returns the RTP header extension properties.
+///
+/// \return the RTP header extension properties
+///
+/// \since QXmpp 1.5
+///
+QVector<QXmppJingleRtpHeaderExtensionProperty> QXmppJingleIq::Content::rtpHeaderExtensionProperties() const
+{
+ return d->rtpHeaderExtensionProperties;
+}
+
+///
+/// Sets the RTP header extension properties.
+///
+/// \param rtpHeaderExtensionProperties RTP header extension properties
+///
+/// \since QXmpp 1.5
+///
+void QXmppJingleIq::Content::setRtpHeaderExtensionProperties(const QVector<QXmppJingleRtpHeaderExtensionProperty> &rtpHeaderExtensionProperties)
+{
+ d->rtpHeaderExtensionProperties = rtpHeaderExtensionProperties;
+}
+
+///
+/// Returns whether mixing of RTP header extensions is allowed corresponding to the
+/// "extmap-allow-mixed" element as specified by
+/// \xep{0293, Jingle RTP Header Extensions Negotiation}.
+///
+/// \return whether mixing of RTP header extensions is allowed
+///
+/// \since QXmpp 1.5
+///
+bool QXmppJingleIq::Content::isRtpHeaderExtensionMixingAllowed() const
+{
+ return d->isRtpHeaderExtensionMixingAllowed;
+}
+
+///
+/// Sets whether mixing of RTP header extensions is allowed corresponding to the
+/// "extmap-allow-mixed" element as specified by
+/// \xep{0293, Jingle RTP Header Extensions Negotiation}.
+///
+/// \param isAllowed whether mixing of RTP header extensions is allowed
+///
+/// \since QXmpp 1.5
+///
+void QXmppJingleIq::Content::setRtpHeaderExtensionMixingAllowed(bool isRtpHeaderExtensionMixingAllowed)
+{
+ d->isRtpHeaderExtensionMixingAllowed = isRtpHeaderExtensionMixingAllowed;
+}
+
+///
/// Returns the fingerprint hash value for the transport key.
///
/// This is used for DTLS-SRTP as defined in \xep{0320}.
@@ -568,6 +662,7 @@ void QXmppJingleIq::Content::parse(const QDomElement &element)
d->isRtpMultiplexingSupported = !descriptionElement.firstChildElement(QStringLiteral("rtcp-mux")).isNull();
parseJingleRtpFeedbackNegotiationElements(descriptionElement, d->rtpFeedbackProperties, d->rtpFeedbackIntervals);
+ parseJingleRtpHeaderExtensionsNegotiationElements(descriptionElement, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed);
QDomElement child = descriptionElement.firstChildElement(QStringLiteral("payload-type"));
while (!child.isNull()) {
@@ -626,6 +721,7 @@ void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const
}
jingleRtpFeedbackNegotiationElementsToXml(writer, d->rtpFeedbackProperties, d->rtpFeedbackIntervals);
+ jingleRtpHeaderExtensionsNegotiationElementsToXml(writer, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed);
for (const auto &payload : d->payloadTypes) {
payload.toXml(writer);
@@ -2162,3 +2258,168 @@ bool QXmppJingleRtpFeedbackInterval::isJingleRtpFeedbackInterval(const QDomEleme
return element.tagName() == QStringLiteral("rtcp-fb-trr-int") &&
element.namespaceURI() == ns_jingle_rtp_feedback_negotiation;
}
+
+class QXmppJingleRtpHeaderExtensionPropertyPrivate : public QSharedData
+{
+public:
+ uint32_t id = 0;
+ QString uri;
+ QXmppJingleRtpHeaderExtensionProperty::Senders senders = QXmppJingleRtpHeaderExtensionProperty::Both;
+ QVector<QXmppSdpParameter> parameters;
+};
+
+///
+/// \enum QXmppJingleRtpHeaderExtensionProperty::Senders
+///
+/// Parties that are allowed to send the negotiated RTP header extension
+///
+
+///
+/// \class QXmppJingleRtpHeaderExtensionProperty
+///
+/// \brief The QXmppJingleRtpHeaderExtensionProperty class represents the
+/// \xep{0294, Jingle RTP Header Extensions Negotiation} "rtp-hdrext" element.
+///
+/// \since QXmpp 1.5
+///
+
+///
+/// Constructs a Jingle RTP header extension property.
+///
+QXmppJingleRtpHeaderExtensionProperty::QXmppJingleRtpHeaderExtensionProperty()
+ : d(new QXmppJingleRtpHeaderExtensionPropertyPrivate())
+{
+}
+
+QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpHeaderExtensionProperty)
+
+///
+/// Returns the ID of the RTP header extension.
+///
+/// The ID is 0 if it is unset.
+///
+/// \return the RTP header extension's ID
+///
+uint32_t QXmppJingleRtpHeaderExtensionProperty::id() const
+{
+ return d->id;
+}
+
+///
+/// Sets the ID of the RTP header extension.
+///
+/// The ID must either be at least 1 and at most 256 or at least 4096 and at most 4351.
+///
+/// \param id RTP header extension's ID
+///
+void QXmppJingleRtpHeaderExtensionProperty::setId(uint32_t id)
+{
+ d->id = id;
+}
+
+///
+/// Returns the URI defning the RTP header extension.
+///
+/// \return the RTP header extension's URI
+///
+QString QXmppJingleRtpHeaderExtensionProperty::uri() const
+{
+ return d->uri;
+}
+
+///
+/// Sets the URI defning the RTP header extension.
+///
+/// \param uri RTP header extension's URI
+///
+void QXmppJingleRtpHeaderExtensionProperty::setUri(const QString &uri)
+{
+ d->uri = uri;
+}
+
+///
+/// Returns the parties that are allowed to send the negotiated RTP header extensions.
+///
+/// \return the parties that are allowed to send the RTP header extensions
+///
+QXmppJingleRtpHeaderExtensionProperty::Senders QXmppJingleRtpHeaderExtensionProperty::senders() const
+{
+ return d->senders;
+}
+
+///
+/// Sets the parties that are allowed to send the negotiated RTP header extensions.
+///
+/// \param senders parties that are allowed to send the RTP header extensions
+///
+void QXmppJingleRtpHeaderExtensionProperty::setSenders(Senders senders)
+{
+ d->senders = senders;
+}
+
+///
+/// Returns the parameters of the RTP header extension.
+///
+/// \return the RTP header extension's parameters
+///
+QVector<QXmppSdpParameter> QXmppJingleRtpHeaderExtensionProperty::parameters() const
+{
+ return d->parameters;
+}
+
+///
+/// Sets the parameters of the RTP header extension.
+///
+/// Additional parameters can be set by this method.
+///
+/// \param parameters RTP header extension's parameters
+///
+void QXmppJingleRtpHeaderExtensionProperty::setParameters(const QVector<QXmppSdpParameter> &parameters)
+{
+ d->parameters = parameters;
+}
+
+/// \cond
+void QXmppJingleRtpHeaderExtensionProperty::parse(const QDomElement &element)
+{
+ if (element.tagName() == QStringLiteral("rtp-hdrext") && element.namespaceURI() == ns_jingle_rtp_header_extensions_negotiation) {
+ d->id = element.attribute(QStringLiteral("id")).toUInt();
+ d->uri = element.attribute(QStringLiteral("uri"));
+
+ if (const auto senders = JINGLE_RTP_HEADER_EXTENSIONS_SENDERS.indexOf(element.attribute(QStringLiteral("senders"))); senders > QXmppJingleRtpHeaderExtensionProperty::Both) {
+ d->senders = static_cast<QXmppJingleRtpHeaderExtensionProperty::Senders>(senders);
+ }
+
+ parseSdpParameters(element, d->parameters);
+ }
+}
+
+void QXmppJingleRtpHeaderExtensionProperty::toXml(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement(QStringLiteral("rtp-hdrext"));
+ writer->writeDefaultNamespace(ns_jingle_rtp_header_extensions_negotiation);
+ helperToXmlAddAttribute(writer, QStringLiteral("id"), QString::number(d->id));
+ helperToXmlAddAttribute(writer, QStringLiteral("uri"), d->uri);
+
+ if (d->senders != QXmppJingleRtpHeaderExtensionProperty::Both) {
+ helperToXmlAddAttribute(writer, QStringLiteral("senders"), JINGLE_RTP_HEADER_EXTENSIONS_SENDERS.at(d->senders));
+ }
+
+ sdpParametersToXml(writer, d->parameters);
+
+ writer->writeEndElement();
+}
+/// \endcond
+
+///
+/// Determines whether the given DOM element is an RTP header extensions property element.
+///
+/// \param element DOM element being checked
+///
+/// \return whether element is an RTP header extension property element
+///
+bool QXmppJingleRtpHeaderExtensionProperty::isJingleRtpHeaderExtensionProperty(const QDomElement &element)
+{
+ return element.tagName() == QStringLiteral("rtp-hdrext") &&
+ element.namespaceURI() == ns_jingle_rtp_header_extensions_negotiation;
+}
diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h
index 02ecc9a5..8dd3e68f 100644
--- a/src/base/QXmppJingleIq.h
+++ b/src/base/QXmppJingleIq.h
@@ -17,6 +17,7 @@ class QXmppJingleIqContentPrivate;
class QXmppJingleIqPrivate;
class QXmppJinglePayloadTypePrivate;
class QXmppJingleRtpFeedbackPropertyPrivate;
+class QXmppJingleRtpHeaderExtensionPropertyPrivate;
class QXmppSdpParameterPrivate;
class QXMPP_EXPORT QXmppSdpParameter
@@ -91,6 +92,45 @@ private:
uint64_t m_value;
};
+class QXMPP_EXPORT QXmppJingleRtpHeaderExtensionProperty
+{
+public:
+ enum Senders {
+ /// The initiator and the sender are allowed.
+ Both,
+ /// Only the initiator is allowed.
+ Initiator,
+ /// Only the responder is allowed.
+ Responder
+ };
+
+ QXmppJingleRtpHeaderExtensionProperty();
+
+ QXMPP_PRIVATE_DECLARE_RULE_OF_SIX(QXmppJingleRtpHeaderExtensionProperty)
+
+ uint32_t id() const;
+ void setId(uint32_t id);
+
+ QString uri() const;
+ void setUri(const QString &uri);
+
+ Senders senders() const;
+ void setSenders(Senders senders);
+
+ QVector<QXmppSdpParameter> parameters() const;
+ void setParameters(const QVector<QXmppSdpParameter> &parameters);
+
+ /// \cond
+ void parse(const QDomElement &element);
+ void toXml(QXmlStreamWriter *writer) const;
+ /// \endcond
+
+ static bool isJingleRtpHeaderExtensionProperty(const QDomElement &element);
+
+private:
+ QSharedDataPointer<QXmppJingleRtpHeaderExtensionPropertyPrivate> d;
+};
+
///
/// \brief The QXmppJinglePayloadType class represents a payload type
/// as specified by \xep{0167}: Jingle RTP Sessions and RFC 5245.
@@ -330,6 +370,12 @@ public:
QVector<QXmppJingleRtpFeedbackInterval> rtpFeedbackIntervals() const;
void setRtpFeedbackIntervals(const QVector<QXmppJingleRtpFeedbackInterval> &rtpFeedbackIntervals);
+ QVector<QXmppJingleRtpHeaderExtensionProperty> rtpHeaderExtensionProperties() const;
+ void setRtpHeaderExtensionProperties(const QVector<QXmppJingleRtpHeaderExtensionProperty> &rtpHeaderExtensionProperties);
+
+ bool isRtpHeaderExtensionMixingAllowed() const;
+ void setRtpHeaderExtensionMixingAllowed(bool isRtpHeaderExtensionMixingAllowed);
+
// XEP-0320: Use of DTLS-SRTP in Jingle Sessions
QByteArray transportFingerprint() const;
void setTransportFingerprint(const QByteArray &fingerprint);