diff options
| author | Melvin Keskin <melvo@olomono.de> | 2022-09-27 22:27:20 +0200 |
|---|---|---|
| committer | Linus Jahn <lnj@kaidan.im> | 2022-10-01 19:50:31 +0200 |
| commit | 1814f67c9a41eb750a56fdccd28843b53be17b0d (patch) | |
| tree | 6b224b53f6fae15609752c4d30c1eb3b155b5efe /src/base | |
| parent | 58646ad17d331f980fa1e03e3831fadea847c2b2 (diff) | |
| download | qxmpp-1814f67c9a41eb750a56fdccd28843b53be17b0d.tar.gz | |
Implement XEP-0294: Jingle RTP Header Extensions Negotiation stanzas
Diffstat (limited to 'src/base')
| -rw-r--r-- | src/base/QXmppConstants.cpp | 2 | ||||
| -rw-r--r-- | src/base/QXmppConstants_p.h | 2 | ||||
| -rw-r--r-- | src/base/QXmppJingleIq.cpp | 263 | ||||
| -rw-r--r-- | src/base/QXmppJingleIq.h | 46 |
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> ¶meters) { +static void sdpParametersToXml(QXmlStreamWriter *writer, const QVector<QXmppSdpParameter> ¶meters) +{ for (const auto ¶meter : 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> ¶meters) +{ + 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> ¶meters); + + /// \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); |
