diff options
| author | Linus Jahn <lnj@kaidan.im> | 2023-05-15 00:00:35 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-15 00:00:35 +0200 |
| commit | 6fe82239fc55b16953f965ea4e20e5fbfe806dd5 (patch) | |
| tree | 8c640ff269f527c7685d07a82517ba040d4d8e7f /src/base/QXmppJingleIq.cpp | |
| parent | fbb96a37f1c118c14fd158173e0d691022183ee3 (diff) | |
| parent | 85006abce021819de6af389d04e88756fac0745a (diff) | |
| download | qxmpp-master.tar.gz | |
XEP-0353: Jingle Message Initiation
Diffstat (limited to 'src/base/QXmppJingleIq.cpp')
| -rw-r--r-- | src/base/QXmppJingleIq.cpp | 2781 |
1 files changed, 0 insertions, 2781 deletions
diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp deleted file mode 100644 index a89f87a6..00000000 --- a/src/base/QXmppJingleIq.cpp +++ /dev/null @@ -1,2781 +0,0 @@ -// SPDX-FileCopyrightText: 2010 Jeremy LainĂ© <jeremy.laine@m4x.org> -// SPDX-FileCopyrightText: 2022 Melvin Keskin <melvo@olomono.de> -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -#include "QXmppJingleIq.h" - -#include "QXmppConstants_p.h" -#include "QXmppUtils.h" - -#include <QDate> -#include <QDateTime> -#include <QDomElement> -#include <QRegularExpression> - -static const int RTP_COMPONENT = 1; - -static const char *jingle_actions[] = { - "content-accept", - "content-add", - "content-modify", - "content-reject", - "content-remove", - "description-info", - "security-info", - "session-accept", - "session-info", - "session-initiate", - "session-terminate", - "transport-accept", - "transport-info", - "transport-reject", - "transport-replace", -}; - -static const char *jingle_reasons[] = { - "", - "alternative-session", - "busy", - "cancel", - "connectivity-error", - "decline", - "expired", - "failed-application", - "failed-transport", - "general-error", - "gone", - "incompatible-parameters", - "media-error", - "security-error", - "success", - "timeout", - "unsupported-applications", - "unsupported-transports", -}; - -static const QStringList JINGLE_RTP_ERROR_CONDITIONS = { - {}, - QStringLiteral("invalid-crypto"), - QStringLiteral("crypto-required") -}; - -static const QStringList JINGLE_RTP_HEADER_EXTENSIONS_SENDERS = { - QStringLiteral("both"), - QStringLiteral("initiator"), - QStringLiteral("responder") -}; - -static QString formatFingerprint(const QByteArray &digest) -{ - QString fingerprint; - const QString hx = digest.toHex().toUpper(); - for (int i = 0; i < hx.size(); i += 2) { - if (!fingerprint.isEmpty()) { - fingerprint += ':'; - } - fingerprint += hx.mid(i, 2); - } - return fingerprint; -} - -static QByteArray parseFingerprint(const QString &fingerprint) -{ - QString z = fingerprint; - z.replace(':', ""); - return QByteArray::fromHex(z.toUtf8()); -} - -static QString addressToSdp(const QHostAddress &host) -{ - return QStringLiteral("IN %1 %2").arg(host.protocol() == QAbstractSocket::IPv6Protocol ? QStringLiteral("IP6") : QStringLiteral("IP4"), host.toString()); -} - -static bool candidateParseSdp(QXmppJingleCandidate *candidate, const QString &sdp) -{ - if (!sdp.startsWith(QStringLiteral("candidate:"))) { - return false; - } - - const QStringList bits = sdp.mid(10).split(" "); - if (bits.size() < 6) { - return false; - } - - candidate->setFoundation(bits[0]); - candidate->setComponent(bits[1].toInt()); - candidate->setProtocol(bits[2].toLower()); - candidate->setPriority(bits[3].toInt()); - candidate->setHost(QHostAddress(bits[4])); - candidate->setPort(bits[5].toInt()); - for (int i = 6; i < bits.size() - 1; i += 2) { - if (bits[i] == QStringLiteral("typ")) { - bool ok; - candidate->setType(QXmppJingleCandidate::typeFromString(bits[i + 1], &ok)); - if (!ok) { - return false; - } - } else if (bits[i] == QStringLiteral("generation")) { - candidate->setGeneration(bits[i + 1].toInt()); - } else { - qWarning() << "Candidate SDP contains unknown attribute" << bits[i]; - return false; - } - } - return true; -} - -static QString candidateToSdp(const QXmppJingleCandidate &candidate) -{ - return QStringLiteral("candidate:%1 %2 %3 %4 %5 %6 typ %7 generation %8").arg(candidate.foundation(), QString::number(candidate.component()), candidate.protocol(), QString::number(candidate.priority()), candidate.host().toString(), QString::number(candidate.port()), QXmppJingleCandidate::typeToString(candidate.type()), QString::number(candidate.generation())); -} - -// Parses all found SDP parameter elements of parent into parameters. -static void parseSdpParameters(const QDomElement &parent, QVector<QXmppSdpParameter> ¶meters) -{ - for (auto childElement = parent.firstChildElement(); - !childElement.isNull(); - childElement = childElement.nextSiblingElement()) { - if (QXmppSdpParameter::isSdpParameter(childElement)) { - QXmppSdpParameter parameter; - parameter.parse(childElement); - parameters.append(parameter); - } - } -} - -// Serializes the SDP parameters. -static void sdpParametersToXml(QXmlStreamWriter *writer, const QVector<QXmppSdpParameter> ¶meters) -{ - for (const auto ¶meter : parameters) { - parameter.toXml(writer); - } -} - -// Parses all found RTP Feedback Negotiation elements inside of parent into properties and -// intervals. -static void parseJingleRtpFeedbackNegotiationElements(const QDomElement &parent, QVector<QXmppJingleRtpFeedbackProperty> &properties, QVector<QXmppJingleRtpFeedbackInterval> &intervals) -{ - for (auto child = parent.firstChildElement(); - !child.isNull(); - child = child.nextSiblingElement()) { - if (QXmppJingleRtpFeedbackProperty::isJingleRtpFeedbackProperty(child)) { - QXmppJingleRtpFeedbackProperty property; - property.parse(child); - properties.append(property); - } else if (QXmppJingleRtpFeedbackInterval::isJingleRtpFeedbackInterval(child)) { - QXmppJingleRtpFeedbackInterval interval; - interval.parse(child); - intervals.append(interval); - } - } -} - -// Serializes the RTP feedback properties and intervals. -static void jingleRtpFeedbackNegotiationElementsToXml(QXmlStreamWriter *writer, const QVector<QXmppJingleRtpFeedbackProperty> &properties, const QVector<QXmppJingleRtpFeedbackInterval> &intervals) -{ - for (const auto &property : properties) { - property.toXml(writer); - } - - for (const auto &interval : intervals) { - interval.toXml(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: - QXmppJingleIqContentPrivate(); - - QString creator; - QString disposition; - QString name; - QString senders; - - QString descriptionMedia; - quint32 descriptionSsrc; - QString descriptionType; - bool isRtpMultiplexingSupported = false; - - QString transportType; - QString transportUser; - QString transportPassword; - - QByteArray transportFingerprint; - QString transportFingerprintHash; - QString transportFingerprintSetup; - - QList<QXmppJinglePayloadType> payloadTypes; - QList<QXmppJingleCandidate> transportCandidates; - - // XEP-0167: Jingle RTP Sessions - std::optional<QXmppJingleRtpEncryption> rtpEncryption; - - // 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() - : descriptionSsrc(0) -{ -} - -/// -/// \enum QXmppJingleIq::Creator -/// -/// Party that originially generated the content type -/// -/// \since QXmpp 1.5 -/// - -/// -/// \struct QXmppJingleIq::RtpSessionStateActive -/// -/// Actively participating in the session after having been on mute or having put the other party on -/// hold -/// -/// \since QXmpp 1.5 -/// - -/// -/// \struct QXmppJingleIq::RtpSessionStateHold -/// -/// Temporarily not listening for media from the other party -/// -/// \since QXmpp 1.5 -/// - -/// -/// \struct QXmppJingleIq::RtpSessionStateUnhold -/// -/// Ending hold state -/// -/// \since QXmpp 1.5 -/// - -/// -/// \struct QXmppJingleIq::RtpSessionStateMuting -/// -/// State for muting or unmuting -/// -/// \since QXmpp 1.5 -/// - -/// -/// \struct QXmppJingleIq::RtpSessionStateRinging -/// -/// State after the callee acknowledged the call but did not yet interacted with it -/// -/// \since QXmpp 1.5 -/// - -/// -/// \typedef QXmppJingleIq::RtpSessionState -/// -/// Contains the state of an RTP session as specified by \xep{0167, Jingle RTP Sessions} -/// Informational Messages. -/// -/// \since QXmpp 1.5 -/// - -/// Constructs an empty content. -QXmppJingleIq::Content::Content() - : d(new QXmppJingleIqContentPrivate()) -{ -} - -/// Copy-constructor. -QXmppJingleIq::Content::Content(const QXmppJingleIq::Content &other) = default; -/// Move-constructor. -QXmppJingleIq::Content::Content(QXmppJingleIq::Content &&) = default; -/// Assignment operator. -QXmppJingleIq::Content &QXmppJingleIq::Content::operator=(const QXmppJingleIq::Content &) = default; -/// Move-assignment operator. -QXmppJingleIq::Content &QXmppJingleIq::Content::operator=(QXmppJingleIq::Content &&) = default; - -QXmppJingleIq::Content::~Content() = default; - -QString QXmppJingleIq::Content::creator() const -{ - return d->creator; -} - -void QXmppJingleIq::Content::setCreator(const QString &creator) -{ - d->creator = creator; -} - -QString QXmppJingleIq::Content::name() const -{ - return d->name; -} - -void QXmppJingleIq::Content::setName(const QString &name) -{ - d->name = name; -} - -QString QXmppJingleIq::Content::senders() const -{ - return d->senders; -} - -void QXmppJingleIq::Content::setSenders(const QString &senders) -{ - d->senders = senders; -} - -QString QXmppJingleIq::Content::descriptionMedia() const -{ - return d->descriptionMedia; -} - -void QXmppJingleIq::Content::setDescriptionMedia(const QString &media) -{ - d->descriptionMedia = media; -} - -/// -/// Returns the description's 32-bit synchronization source for the media stream as specified by -/// \xep{0167, Jingle RTP Sessions} and RFC 3550. -/// -/// \since QXmpp 0.9 -/// -quint32 QXmppJingleIq::Content::descriptionSsrc() const -{ - return d->descriptionSsrc; -} - -/// -/// Sets the description's 32-bit synchronization source for the media stream as specified by -/// \xep{0167, Jingle RTP Sessions} and RFC 3550. -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleIq::Content::setDescriptionSsrc(quint32 ssrc) -{ - d->descriptionSsrc = ssrc; -} - -/// -/// Returns whether multiplexing of RTP data and control packets on a single port is supported as -/// specified by \xep{0167, Jingle RTP Sessions} and RFC 5761. -/// -/// \return whether multiplexing of RTP data and control packets is supported -/// -/// \since QXmpp 1.5 -/// -bool QXmppJingleIq::Content::isRtpMultiplexingSupported() const -{ - return d->isRtpMultiplexingSupported; -} - -/// -/// Sets whether multiplexing of RTP data and control packets on a single port is supported as -/// specified by \xep{0167, Jingle RTP Sessions} and RFC 5761. -/// -/// \param isRtpMultiplexingSupported whether multiplexing of RTP data and control packets is -/// supported -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::Content::setRtpMultiplexingSupported(bool isRtpMultiplexingSupported) -{ - d->isRtpMultiplexingSupported = isRtpMultiplexingSupported; -} - -/// -/// Returns the encryption used for SRTP negotiation as specified by -/// \xep{0167, Jingle RTP Sessions}. -/// -/// \return the RTP encryption via SRTP -/// -/// \since QXmpp 1.5 -/// -std::optional<QXmppJingleRtpEncryption> QXmppJingleIq::Content::rtpEncryption() const -{ - return d->rtpEncryption; -} - -/// -/// Sets the encryption used for SRTP negotiation as specified by \xep{0167, Jingle RTP Sessions}. -/// -/// \param rtpEncryption RTP encryption via SRTP -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::Content::setRtpEncryption(const std::optional<QXmppJingleRtpEncryption> &rtpEncryption) -{ - d->rtpEncryption = rtpEncryption; -} - -void QXmppJingleIq::Content::addPayloadType(const QXmppJinglePayloadType &payload) -{ - d->descriptionType = ns_jingle_rtp; - d->payloadTypes << payload; -} - -QList<QXmppJinglePayloadType> QXmppJingleIq::Content::payloadTypes() const -{ - return d->payloadTypes; -} - -void QXmppJingleIq::Content::setPayloadTypes(const QList<QXmppJinglePayloadType> &payloadTypes) -{ - d->descriptionType = payloadTypes.isEmpty() ? QString() : ns_jingle_rtp; - d->payloadTypes = payloadTypes; -} - -void QXmppJingleIq::Content::addTransportCandidate(const QXmppJingleCandidate &candidate) -{ - d->transportType = ns_jingle_ice_udp; - d->transportCandidates << candidate; -} - -QList<QXmppJingleCandidate> QXmppJingleIq::Content::transportCandidates() const -{ - return d->transportCandidates; -} - -/// -/// Sets a list of transport candidates. -/// -/// \since QXmpp 0.9.2 -/// -void QXmppJingleIq::Content::setTransportCandidates(const QList<QXmppJingleCandidate> &candidates) -{ - d->transportType = candidates.isEmpty() ? QString() : ns_jingle_ice_udp; - d->transportCandidates = candidates; -} - -QString QXmppJingleIq::Content::transportUser() const -{ - return d->transportUser; -} - -void QXmppJingleIq::Content::setTransportUser(const QString &user) -{ - d->transportUser = user; -} - -QString QXmppJingleIq::Content::transportPassword() const -{ - return d->transportPassword; -} - -void QXmppJingleIq::Content::setTransportPassword(const QString &password) -{ - d->transportPassword = password; -} - -/// -/// Returns the properties of RTP feedback. -/// -/// \return the RTP feedback properties -/// -/// \since QXmpp 1.5 -/// -QVector<QXmppJingleRtpFeedbackProperty> QXmppJingleIq::Content::rtpFeedbackProperties() const -{ - return d->rtpFeedbackProperties; -} - -/// -/// Sets the properties of RTP feedback. -/// -/// \param rtpFeedbackProperties RTP feedback properties -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::Content::setRtpFeedbackProperties(const QVector<QXmppJingleRtpFeedbackProperty> &rtpFeedbackProperties) -{ - d->rtpFeedbackProperties = rtpFeedbackProperties; -} - -/// -/// Returns the intervals of RTP feedback. -/// -/// \return the RTP feedback intervals -/// -/// \since QXmpp 1.5 -/// -QVector<QXmppJingleRtpFeedbackInterval> QXmppJingleIq::Content::rtpFeedbackIntervals() const -{ - return d->rtpFeedbackIntervals; -} - -/// -/// Sets the intervals of RTP feedback. -/// -/// \param rtpFeedbackIntervals RTP feedback intervals -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::Content::setRtpFeedbackIntervals(const QVector<QXmppJingleRtpFeedbackInterval> &rtpFeedbackIntervals) -{ - d->rtpFeedbackIntervals = rtpFeedbackIntervals; -} - -/// -/// 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}. -/// -/// \since QXmpp 0.9 -/// -QByteArray QXmppJingleIq::Content::transportFingerprint() const -{ - return d->transportFingerprint; -} - -/// -/// Sets the fingerprint hash value for the transport key. -/// -/// This is used for DTLS-SRTP as defined in \xep{0320}. -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleIq::Content::setTransportFingerprint(const QByteArray &fingerprint) -{ - d->transportFingerprint = fingerprint; -} - -/// -/// Returns the fingerprint hash algorithm for the transport key. -/// -/// This is used for DTLS-SRTP as defined in \xep{0320}. -/// -/// \since QXmpp 0.9 -/// -QString QXmppJingleIq::Content::transportFingerprintHash() const -{ - return d->transportFingerprintHash; -} - -/// -/// Sets the fingerprint hash algorithm for the transport key. -/// -/// This is used for DTLS-SRTP as defined in \xep{0320}. -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleIq::Content::setTransportFingerprintHash(const QString &hash) -{ - d->transportFingerprintHash = hash; -} - -/// -/// Returns the setup role for the encrypted transport. -/// -/// This is used for DTLS-SRTP as defined in \xep{0320}. -/// -/// \since QXmpp 0.9 -/// -QString QXmppJingleIq::Content::transportFingerprintSetup() const -{ - return d->transportFingerprintSetup; -} - -/// -/// Sets the setup role for the encrypted transport. -/// -/// This is used for DTLS-SRTP as defined in \xep{0320}. -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleIq::Content::setTransportFingerprintSetup(const QString &setup) -{ - d->transportFingerprintSetup = setup; -} - -/// \cond -void QXmppJingleIq::Content::parse(const QDomElement &element) -{ - d->creator = element.attribute(QStringLiteral("creator")); - d->disposition = element.attribute(QStringLiteral("disposition")); - d->name = element.attribute(QStringLiteral("name")); - d->senders = element.attribute(QStringLiteral("senders")); - - // description - QDomElement descriptionElement = element.firstChildElement(QStringLiteral("description")); - d->descriptionType = descriptionElement.namespaceURI(); - d->descriptionMedia = descriptionElement.attribute(QStringLiteral("media")); - d->descriptionSsrc = descriptionElement.attribute(QStringLiteral("ssrc")).toULong(); - d->isRtpMultiplexingSupported = !descriptionElement.firstChildElement(QStringLiteral("rtcp-mux")).isNull(); - - for (auto childElement = descriptionElement.firstChildElement(); - !childElement.isNull(); - childElement = childElement.nextSiblingElement()) { - if (QXmppJingleRtpEncryption::isJingleRtpEncryption(childElement)) { - QXmppJingleRtpEncryption encryption; - encryption.parse(childElement); - d->rtpEncryption = encryption; - break; - } - } - - parseJingleRtpFeedbackNegotiationElements(descriptionElement, d->rtpFeedbackProperties, d->rtpFeedbackIntervals); - parseJingleRtpHeaderExtensionsNegotiationElements(descriptionElement, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed); - - QDomElement child = descriptionElement.firstChildElement(QStringLiteral("payload-type")); - while (!child.isNull()) { - QXmppJinglePayloadType payload; - payload.parse(child); - d->payloadTypes << payload; - child = child.nextSiblingElement(QStringLiteral("payload-type")); - } - - // transport - QDomElement transportElement = element.firstChildElement(QStringLiteral("transport")); - d->transportType = transportElement.namespaceURI(); - d->transportUser = transportElement.attribute(QStringLiteral("ufrag")); - d->transportPassword = transportElement.attribute(QStringLiteral("pwd")); - child = transportElement.firstChildElement(QStringLiteral("candidate")); - while (!child.isNull()) { - QXmppJingleCandidate candidate; - candidate.parse(child); - d->transportCandidates << candidate; - child = child.nextSiblingElement(QStringLiteral("candidate")); - } - - /// XEP-0320 - child = transportElement.firstChildElement(QStringLiteral("fingerprint")); - if (!child.isNull()) { - d->transportFingerprint = parseFingerprint(child.text()); - d->transportFingerprintHash = child.attribute(QStringLiteral("hash")); - d->transportFingerprintSetup = child.attribute(QStringLiteral("setup")); - } -} - -void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const -{ - if (d->creator.isEmpty() || d->name.isEmpty()) { - return; - } - - writer->writeStartElement(QStringLiteral("content")); - helperToXmlAddAttribute(writer, QStringLiteral("creator"), d->creator); - helperToXmlAddAttribute(writer, QStringLiteral("disposition"), d->disposition); - helperToXmlAddAttribute(writer, QStringLiteral("name"), d->name); - helperToXmlAddAttribute(writer, QStringLiteral("senders"), d->senders); - - // description - if (!d->descriptionType.isEmpty() || !d->payloadTypes.isEmpty()) { - writer->writeStartElement(QStringLiteral("description")); - writer->writeDefaultNamespace(d->descriptionType); - helperToXmlAddAttribute(writer, QStringLiteral("media"), d->descriptionMedia); - - if (d->descriptionSsrc) { - writer->writeAttribute(QStringLiteral("ssrc"), QString::number(d->descriptionSsrc)); - } - - if (d->isRtpMultiplexingSupported) { - writer->writeEmptyElement(QStringLiteral("rtcp-mux")); - } - - if (d->rtpEncryption) { - d->rtpEncryption->toXml(writer); - } - - jingleRtpFeedbackNegotiationElementsToXml(writer, d->rtpFeedbackProperties, d->rtpFeedbackIntervals); - jingleRtpHeaderExtensionsNegotiationElementsToXml(writer, d->rtpHeaderExtensionProperties, d->isRtpHeaderExtensionMixingAllowed); - - for (const auto &payload : d->payloadTypes) { - payload.toXml(writer); - } - - writer->writeEndElement(); - } - - // transport - if (!d->transportType.isEmpty() || !d->transportCandidates.isEmpty()) { - writer->writeStartElement(QStringLiteral("transport")); - writer->writeDefaultNamespace(d->transportType); - helperToXmlAddAttribute(writer, QStringLiteral("ufrag"), d->transportUser); - helperToXmlAddAttribute(writer, QStringLiteral("pwd"), d->transportPassword); - for (const auto &candidate : d->transportCandidates) { - candidate.toXml(writer); - } - - // XEP-0320: Use of DTLS-SRTP in Jingle Sessions - if (!d->transportFingerprint.isEmpty() && !d->transportFingerprintHash.isEmpty()) { - writer->writeStartElement(QStringLiteral("fingerprint")); - writer->writeDefaultNamespace(ns_jingle_dtls); - writer->writeAttribute(QStringLiteral("hash"), d->transportFingerprintHash); - writer->writeAttribute(QStringLiteral("setup"), d->transportFingerprintSetup); - writer->writeCharacters(formatFingerprint(d->transportFingerprint)); - writer->writeEndElement(); - } - writer->writeEndElement(); - } - - writer->writeEndElement(); -} - -bool QXmppJingleIq::Content::parseSdp(const QString &sdp) -{ - QList<QXmppJinglePayloadType> payloads; - for (auto &line : sdp.split(QChar(u'\n'))) { - if (line.endsWith('\r')) { - line.resize(line.size() - 1); - } - if (line.startsWith(QStringLiteral("a="))) { - int idx = line.indexOf(':'); - const QString attrName = idx != -1 ? line.mid(2, idx - 2) : line.mid(2); - const QString attrValue = idx != -1 ? line.mid(idx + 1) : ""; - - if (attrName == QStringLiteral("candidate")) { - QXmppJingleCandidate candidate; - if (!candidateParseSdp(&candidate, line.mid(2))) { - qWarning() << "Could not parse candidate" << line; - return false; - } - addTransportCandidate(candidate); - } else if (attrName == QStringLiteral("fingerprint")) { - const QStringList bits = attrValue.split(' '); - if (bits.size() > 1) { - d->transportFingerprintHash = bits[0]; - d->transportFingerprint = parseFingerprint(bits[1]); - } - } else if (attrName == QStringLiteral("fmtp")) { - int spIdx = attrValue.indexOf(' '); - if (spIdx == -1) { - qWarning() << "Could not parse payload parameters" << line; - return false; - } - const int id = attrValue.left(spIdx).toInt(); - const QString paramStr = attrValue.mid(spIdx + 1); - for (auto &payload : payloads) { - if (payload.id() == id) { - QMap<QString, QString> params; - if (payload.name() == QStringLiteral("telephone-event")) { - params.insert(QStringLiteral("events"), paramStr); - } else { - thread_local static const auto regex = QRegularExpression(";\\s*"); - const auto paramParts = paramStr.split(regex); - for (const auto &p : paramParts) { - const QStringList bits = p.split('='); - if (bits.size() == 2) { - params.insert(bits.at(0), bits.at(1)); - } - } - } - payload.setParameters(params); - } - } - } else if (attrName == QStringLiteral("rtpmap")) { - // payload type map - const QStringList bits = attrValue.split(' '); - if (bits.size() != 2) { - continue; - } - bool ok = false; - const int id = bits[0].toInt(&ok); - if (!ok) { - continue; - } - - const QStringList args = bits[1].split('/'); - for (auto &payload : payloads) { - if (payload.id() == id) { - payload.setName(args[0]); - if (args.size() > 1) { - payload.setClockrate(args[1].toInt()); - } - if (args.size() > 2) { - payload.setChannels(args[2].toInt()); - } - } - } - } else if (attrName == QStringLiteral("ice-ufrag")) { - d->transportUser = attrValue; - } else if (attrName == QStringLiteral("ice-pwd")) { - d->transportPassword = attrValue; - } else if (attrName == QStringLiteral("setup")) { - d->transportFingerprintSetup = attrValue; - } else if (attrName == QStringLiteral("ssrc")) { - const QStringList bits = attrValue.split(' '); - if (bits.isEmpty()) { - qWarning() << "Could not parse ssrc" << line; - return false; - } - d->descriptionSsrc = bits[0].toULong(); - } - } else if (line.startsWith(QStringLiteral("m="))) { - // FIXME: what do we do with the profile (bits[2]) ? - QStringList bits = line.mid(2).split(' '); - if (bits.size() < 3) { - qWarning() << "Could not parse media" << line; - return false; - } - d->descriptionMedia = bits[0]; - - // parse payload types - for (int i = 3; i < bits.size(); ++i) { - bool ok = false; - int id = bits[i].toInt(&ok); - if (!ok) { - continue; - } - QXmppJinglePayloadType payload; - payload.setId(id); - payloads << payload; - } - } - } - setPayloadTypes(payloads); - return true; -} - -static bool candidateLessThan(const QXmppJingleCandidate &c1, const QXmppJingleCandidate &c2) -{ - if (c1.type() == c2.type()) { - return c1.priority() > c2.priority(); - } else { - return c1.type() == QXmppJingleCandidate::ServerReflexiveType; - } -} - -QString QXmppJingleIq::Content::toSdp() const -{ - // get default candidate - QHostAddress localRtpAddress = QHostAddress::Any; - quint16 localRtpPort = 0; - QList<QXmppJingleCandidate> sortedCandidates = d->transportCandidates; - std::sort(sortedCandidates.begin(), sortedCandidates.end(), candidateLessThan); - for (const auto &candidate : sortedCandidates) { - if (candidate.component() == RTP_COMPONENT) { - localRtpAddress = candidate.host(); - localRtpPort = candidate.port(); - break; - } - } - - QStringList sdp; - - // media - QString payloads; - QStringList attrs; - for (const QXmppJinglePayloadType &payload : d->payloadTypes) { - payloads += " " + QString::number(payload.id()); - QString rtpmap = QString::number(payload.id()) + " " + payload.name() + "/" + QString::number(payload.clockrate()); - if (payload.channels() > 1) { - rtpmap += "/" + QString::number(payload.channels()); - } - attrs << "a=rtpmap:" + rtpmap; - - // payload parameters - QStringList paramList; - const QMap<QString, QString> params = payload.parameters(); - if (payload.name() == QStringLiteral("telephone-event")) { - if (params.contains(QStringLiteral("events"))) { - paramList << params.value(QStringLiteral("events")); - } - } else { - QMap<QString, QString>::const_iterator i; - for (i = params.begin(); i != params.end(); ++i) { - paramList << i.key() + QStringLiteral("=") + i.value(); - } - } - if (!paramList.isEmpty()) { - attrs << QStringLiteral("a=fmtp:") + QByteArray::number(payload.id()) + QStringLiteral(" ") + paramList.join("; "); - } - } - sdp << QStringLiteral("m=%1 %2 RTP/AVP%3").arg(d->descriptionMedia, QString::number(localRtpPort), payloads); - sdp << QStringLiteral("c=%1").arg(addressToSdp(localRtpAddress)); - sdp += attrs; - - // transport - for (const auto &candidate : d->transportCandidates) { - sdp << QStringLiteral("a=%1").arg(candidateToSdp(candidate)); - } - if (!d->transportUser.isEmpty()) { - sdp << QStringLiteral("a=ice-ufrag:%1").arg(d->transportUser); - } - if (!d->transportPassword.isEmpty()) { - sdp << QStringLiteral("a=ice-pwd:%1").arg(d->transportPassword); - } - if (!d->transportFingerprint.isEmpty() && !d->transportFingerprintHash.isEmpty()) { - sdp << QStringLiteral("a=fingerprint:%1 %2").arg(d->transportFingerprintHash, formatFingerprint(d->transportFingerprint)); - } - if (!d->transportFingerprintSetup.isEmpty()) { - sdp << QStringLiteral("a=setup:%1").arg(d->transportFingerprintSetup); - } - - return sdp.join("\r\n") + "\r\n"; -} - -/// \endcond - -/// -/// \enum QXmppJingleIq::Reason::RtpErrorCondition -/// -/// Condition of an RTP-specific error -/// -/// \since QXmpp 1.5 -/// - -QXmppJingleIq::Reason::Reason() - : m_type(None) -{ -} - -/// Returns the reason's textual description. - -QString QXmppJingleIq::Reason::text() const -{ - return m_text; -} - -/// Sets the reason's textual description. - -void QXmppJingleIq::Reason::setText(const QString &text) -{ - m_text = text; -} - -/// Gets the reason's type. - -QXmppJingleIq::Reason::Type QXmppJingleIq::Reason::type() const -{ - return m_type; -} - -/// Sets the reason's type. - -void QXmppJingleIq::Reason::setType(QXmppJingleIq::Reason::Type type) -{ - m_type = type; -} - -/// -/// Returns the RTP error condition as specified by \xep{0167, Jingle RTP Sessions}. -/// -/// \return the RTP error condition -/// -/// \since QXmpp 1.5 -/// -QXmppJingleIq::Reason::RtpErrorCondition QXmppJingleIq::Reason::rtpErrorCondition() const -{ - return m_rtpErrorCondition; -} - -/// -/// Sets the RTP error condition as specified by \xep{0167, Jingle RTP Sessions}. -/// -/// \param rtpErrorCondition RTP error condition -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::Reason::setRtpErrorCondition(RtpErrorCondition rtpErrorCondition) -{ - m_rtpErrorCondition = rtpErrorCondition; -} - -/// \cond -void QXmppJingleIq::Reason::parse(const QDomElement &element) -{ - m_text = element.firstChildElement(QStringLiteral("text")).text(); - for (int i = AlternativeSession; i <= UnsupportedTransports; i++) { - if (!element.firstChildElement(jingle_reasons[i]).isNull()) { - m_type = static_cast<Type>(i); - break; - } - } - - for (auto child = element.firstChildElement(); - !child.isNull(); - child = child.nextSiblingElement()) { - if (child.namespaceURI() == ns_jingle_rtp_errors) { - if (const auto index = JINGLE_RTP_ERROR_CONDITIONS.indexOf(child.tagName()); - index != -1) { - m_rtpErrorCondition = RtpErrorCondition(index); - } - break; - } - } -} - -void QXmppJingleIq::Reason::toXml(QXmlStreamWriter *writer) const -{ - if (m_type < AlternativeSession || m_type > UnsupportedTransports) { - return; - } - - writer->writeStartElement(QStringLiteral("reason")); - if (!m_text.isEmpty()) { - helperToXmlAddTextElement(writer, QStringLiteral("text"), m_text); - } - writer->writeEmptyElement(jingle_reasons[m_type]); - - if (m_rtpErrorCondition != NoErrorCondition) { - writer->writeStartElement(JINGLE_RTP_ERROR_CONDITIONS.at(m_rtpErrorCondition)); - writer->writeDefaultNamespace(ns_jingle_rtp_errors); - writer->writeEndElement(); - } - - writer->writeEndElement(); -} -/// \endcond - -class QXmppJingleIqPrivate : public QSharedData -{ -public: - QXmppJingleIqPrivate(); - - QXmppJingleIq::Action action; - QString initiator; - QString responder; - QString sid; - - QString mujiGroupChatJid; - - QList<QXmppJingleIq::Content> contents; - QXmppJingleIq::Reason reason; - - std::optional<QXmppJingleIq::RtpSessionState> rtpSessionState; -}; - -QXmppJingleIqPrivate::QXmppJingleIqPrivate() - : action(QXmppJingleIq::ContentAccept) -{ -} - -/// Constructs a QXmppJingleIq. -QXmppJingleIq::QXmppJingleIq() - : d(new QXmppJingleIqPrivate()) -{ -} - -/// Copy-constructor. -QXmppJingleIq::QXmppJingleIq(const QXmppJingleIq &) = default; -/// Move-constructor. -QXmppJingleIq::QXmppJingleIq(QXmppJingleIq &&) = default; - -QXmppJingleIq::~QXmppJingleIq() = default; - -/// Assignment operator. -QXmppJingleIq &QXmppJingleIq::operator=(const QXmppJingleIq &) = default; -/// Move-assignment operator. -QXmppJingleIq &QXmppJingleIq::operator=(QXmppJingleIq &&) = default; - -/// -/// Returns the Jingle IQ's action. -/// -QXmppJingleIq::Action QXmppJingleIq::action() const -{ - return d->action; -} - -/// Sets the Jingle IQ's action. -/// -/// \param action - -void QXmppJingleIq::setAction(QXmppJingleIq::Action action) -{ - d->action = action; -} - -/// -/// Adds an element to the IQ's content elements. -/// -/// \since QXmpp 0.9.2 -/// -void QXmppJingleIq::addContent(const QXmppJingleIq::Content &content) -{ - d->contents << content; -} - -/// -/// Returns the IQ's content elements. -/// -/// \since QXmpp 0.9.2 -/// -QList<QXmppJingleIq::Content> QXmppJingleIq::contents() const -{ - return d->contents; -} - -/// -/// Sets the IQ's content elements. -/// -/// \since QXmpp 0.9.2 -/// -void QXmppJingleIq::setContents(const QList<QXmppJingleIq::Content> &contents) -{ - d->contents = contents; -} - -/// Returns the session initiator. - -QString QXmppJingleIq::initiator() const -{ - return d->initiator; -} - -/// Sets the session initiator. -/// -/// \param initiator - -void QXmppJingleIq::setInitiator(const QString &initiator) -{ - d->initiator = initiator; -} - -/// Returns a reference to the IQ's reason element. - -QXmppJingleIq::Reason &QXmppJingleIq::reason() -{ - return d->reason; -} - -/// Returns a const reference to the IQ's reason element. - -const QXmppJingleIq::Reason &QXmppJingleIq::reason() const -{ - return d->reason; -} - -/// Returns the session responder. - -QString QXmppJingleIq::responder() const -{ - return d->responder; -} - -/// Sets the session responder. -/// -/// \param responder - -void QXmppJingleIq::setResponder(const QString &responder) -{ - d->responder = responder; -} - -/// -/// Returns true if the call is ringing. -/// -/// \deprecated This method is deprecated since QXmpp 1.5. Use \c QXmppJingleIq::rtpSessionState() -/// instead. -/// -bool QXmppJingleIq::ringing() const -{ - if (d->rtpSessionState) { - return std::holds_alternative<RtpSessionStateRinging>(*d->rtpSessionState); - } - - return false; -} - -/// -/// Set to true if the call is ringing. -/// -/// \param ringing -/// -/// \deprecated This method is deprecated since QXmpp 1.5. Use -/// \c QXmppJingleIq::setRtpSessionState() instead. -/// -void QXmppJingleIq::setRinging(bool ringing) -{ - if (ringing) { - d->rtpSessionState = RtpSessionStateRinging(); - } else { - d->rtpSessionState = std::nullopt; - } -} - -/// Returns the session ID. -QString QXmppJingleIq::sid() const -{ - return d->sid; -} - -/// Sets the session ID. -/// -/// \param sid - -void QXmppJingleIq::setSid(const QString &sid) -{ - d->sid = sid; -} - -/// -/// Returns the JID of the \xep{0272, Multiparty Jingle (Muji)} group chat. -/// -/// \return the Muji group chat JID -/// -/// \since QXmpp 1.5 -/// -QString QXmppJingleIq::mujiGroupChatJid() const -{ - return d->mujiGroupChatJid; -} - -/// -/// Sets the JID of the \xep{0272, Multiparty Jingle (Muji)} group chat. -/// -/// \param mujiGroupChatJid Muji group chat JID -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::setMujiGroupChatJid(const QString &mujiGroupChatJid) -{ - d->mujiGroupChatJid = mujiGroupChatJid; -} - -/// -/// Returns the state of an RTP session as specified by \xep{0167, Jingle RTP Sessions} -/// Informational Messages. -/// -/// \return the session's state -/// -/// \since QXmpp 1.5 -/// -std::optional<QXmppJingleIq::RtpSessionState> QXmppJingleIq::rtpSessionState() const -{ - return d->rtpSessionState; -} - -/// -/// Sets the state of an RTP session as specified by \xep{0167, Jingle RTP Sessions} Informational -/// Messages. -/// -/// The appropriate action is set as well. -/// Thus, it is not needed to set it manually. -/// -/// \param rtpSessionState session's state -/// -/// \since QXmpp 1.5 -/// -void QXmppJingleIq::setRtpSessionState(const std::optional<RtpSessionState> &rtpSessionState) -{ - d->rtpSessionState = rtpSessionState; - d->action = Action::SessionInfo; -} - -/// \cond -bool QXmppJingleIq::isJingleIq(const QDomElement &element) -{ - QDomElement jingleElement = element.firstChildElement(QStringLiteral("jingle")); - return (jingleElement.namespaceURI() == ns_jingle); -} - -void QXmppJingleIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement jingleElement = element.firstChildElement(QStringLiteral("jingle")); - const QString action = jingleElement.attribute(QStringLiteral("action")); - for (int i = ContentAccept; i <= TransportReplace; i++) { - if (action == jingle_actions[i]) { - d->action = static_cast<Action>(i); - break; - } - } - d->initiator = jingleElement.attribute(QStringLiteral("initiator")); - d->responder = jingleElement.attribute(QStringLiteral("responder")); - d->sid = jingleElement.attribute(QStringLiteral("sid")); - - // XEP-0272: Multiparty Jingle (Muji) - if (const auto mujiGroupChatElement = jingleElement.firstChildElement(QStringLiteral("muji")); - mujiGroupChatElement.namespaceURI() == ns_muji) { - d->mujiGroupChatJid = mujiGroupChatElement.attribute(QStringLiteral("room")); - } - - // content - d->contents.clear(); - QDomElement contentElement = jingleElement.firstChildElement(QStringLiteral("content")); - while (!contentElement.isNull()) { - Content content; - content.parse(contentElement); - addContent(content); - contentElement = contentElement.nextSiblingElement(QStringLiteral("content")); - } - QDomElement reasonElement = jingleElement.firstChildElement(QStringLiteral("reason")); - d->reason.parse(reasonElement); - - for (auto childElement = jingleElement.firstChildElement(); - !childElement.isNull(); - childElement = childElement.nextSiblingElement()) { - if (childElement.namespaceURI() == ns_jingle_rtp_info) { - const auto elementTag = childElement.tagName(); - - if (elementTag == QStringLiteral("active")) { - d->rtpSessionState = RtpSessionStateActive(); - } else if (elementTag == QStringLiteral("hold")) { - d->rtpSessionState = RtpSessionStateHold(); - } else if (elementTag == QStringLiteral("unhold")) { - d->rtpSessionState = RtpSessionStateUnhold(); - } else if (const auto isMute = elementTag == QStringLiteral("mute"); isMute || elementTag == QStringLiteral("unmute")) { - RtpSessionStateMuting muting; - muting.isMute = isMute; - - if (const auto creator = childElement.attribute(QStringLiteral("creator")); creator == QStringLiteral("initiator")) { - muting.creator = Initiator; - } else if (creator == QStringLiteral("responder")) { - muting.creator = Responder; - } - - muting.name = childElement.attribute(QStringLiteral("name")); - - d->rtpSessionState = muting; - } else if (elementTag == QStringLiteral("ringing")) { - d->rtpSessionState = RtpSessionStateRinging(); - } - } - } -} - -void QXmppJingleIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("jingle")); - writer->writeDefaultNamespace(ns_jingle); - helperToXmlAddAttribute(writer, QStringLiteral("action"), jingle_actions[d->action]); - helperToXmlAddAttribute(writer, QStringLiteral("initiator"), d->initiator); - helperToXmlAddAttribute(writer, QStringLiteral("responder"), d->responder); - helperToXmlAddAttribute(writer, QStringLiteral("sid"), d->sid); - - // XEP-0272: Multiparty Jingle (Muji) - if (!d->mujiGroupChatJid.isEmpty()) { - writer->writeStartElement(QStringLiteral("muji")); - writer->writeDefaultNamespace(ns_muji); - helperToXmlAddAttribute(writer, QStringLiteral("room"), d->mujiGroupChatJid); - writer->writeEndElement(); - } - - for (const auto &content : d->contents) { - content.toXml(writer); - } - - d->reason.toXml(writer); - - const auto writeStartElementWithNamespace = [=](const QString &tagName) { - writer->writeStartElement(tagName); - writer->writeDefaultNamespace(ns_jingle_rtp_info); - }; - - if (d->rtpSessionState) { - if (std::holds_alternative<RtpSessionStateActive>(*d->rtpSessionState)) { - writeStartElementWithNamespace(QStringLiteral("active")); - } else if (std::holds_alternative<RtpSessionStateHold>(*d->rtpSessionState)) { - writeStartElementWithNamespace(QStringLiteral("hold")); - } else if (std::holds_alternative<RtpSessionStateUnhold>(*d->rtpSessionState)) { - writeStartElementWithNamespace(QStringLiteral("unhold")); - } else if (auto rtpSessionStateMuting = std::get_if<RtpSessionStateMuting>(&(*d->rtpSessionState))) { - if (rtpSessionStateMuting->isMute) { - writeStartElementWithNamespace(QStringLiteral("mute")); - } else { - writeStartElementWithNamespace(QStringLiteral("unmute")); - } - - if (rtpSessionStateMuting->creator == Initiator) { - helperToXmlAddAttribute(writer, QStringLiteral("creator"), QStringLiteral("initiator")); - } else if (rtpSessionStateMuting->creator == Responder) { - helperToXmlAddAttribute(writer, QStringLiteral("creator"), QStringLiteral("responder")); - } - - helperToXmlAddAttribute(writer, QStringLiteral("name"), rtpSessionStateMuting->name); - } else { - writeStartElementWithNamespace(QStringLiteral("ringing")); - } - - writer->writeEndElement(); - } - - writer->writeEndElement(); -} -/// \endcond - -class QXmppJingleCandidatePrivate : public QSharedData -{ -public: - QXmppJingleCandidatePrivate(); - - int component; - QString foundation; - int generation; - QHostAddress host; - QString id; - int network; - quint16 port; - QString protocol; - int priority; - QXmppJingleCandidate::Type type; -}; - -QXmppJingleCandidatePrivate::QXmppJingleCandidatePrivate() - : component(0), generation(0), network(0), port(0), priority(0), type(QXmppJingleCandidate::HostType) -{ -} - -/// -/// Constructs an empty candidate. -/// -QXmppJingleCandidate::QXmppJingleCandidate() - : d(new QXmppJingleCandidatePrivate()) -{ -} - -/// Copy-constructor. -QXmppJingleCandidate::QXmppJingleCandidate(const QXmppJingleCandidate &other) = default; -/// Move-constructor. -QXmppJingleCandidate::QXmppJingleCandidate(QXmppJingleCandidate &&) = default; -QXmppJingleCandidate::~QXmppJingleCandidate() = default; -/// Assignment operator. -QXmppJingleCandidate &QXmppJingleCandidate::operator=(const QXmppJingleCandidate &other) = default; -/// Move-assignment operator. -QXmppJingleCandidate &QXmppJingleCandidate::operator=(QXmppJingleCandidate &&) = default; - -/// Returns the candidate's component ID. - -int QXmppJingleCandidate::component() const -{ - return d->component; -} - -/// Sets the candidates's component ID. -/// -/// \param component - -void QXmppJingleCandidate::setComponent(int component) -{ - d->component = component; -} - -/// -/// Returns the candidate's foundation. -/// -/// \since QXmpp 0.9 -/// -QString QXmppJingleCandidate::foundation() const -{ - return d->foundation; -} - -/// -/// Sets the candidate's foundation. -/// -/// \param foundation -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleCandidate::setFoundation(const QString &foundation) -{ - d->foundation = foundation; -} - -/// -/// Returns the candidate's generation. -/// -/// \since QXmpp 0.9 -/// -int QXmppJingleCandidate::generation() const -{ - return d->generation; -} - -/// -/// Sets the candidate's generation. -/// -/// \param generation -/// -/// \since QXmpp 0.9 -/// -void QXmppJingleCandidate::setGeneration(int generation) -{ - d->generation = generation; -} - -/// Returns the candidate's host address. -/// - -QHostAddress QXmppJingleCandidate::host() const -{ - return d->host; -} - -/// Sets the candidate's host address. -/// -/// \param host - -void QXmppJingleCandidate::setHost(const QHostAddress &host) -{ - d->host = host; -} - -/// Returns the candidate's unique identifier. -/// - -QString QXmppJingleCandidate::id() const -{ - return d->id; -} - -/// Sets the candidate's unique identifier. -/// -/// \param id - -void QXmppJingleCandidate::setId(const QString &id) -{ - d->id = id; -} - -/// Returns the network index (starting at 0) the candidate is on. -/// - -int QXmppJingleCandidate::network() const -{ - return d->network; -} - -/// Sets the network index (starting at 0) the candidate is on. -/// -/// \param network - -void QXmppJingleCandidate::setNetwork(int network) -{ - d->network = network; -} - -/// Returns the candidate's port number. -/// - -quint16 QXmppJingleCandidate::port() const -{ - return d->port; -} - -/// Sets the candidate's port number. -/// -/// \param port - -void QXmppJingleCandidate::setPort(quint16 port) -{ - d->port = port; -} - -/// Returns the candidate's priority. -/// - -int QXmppJingleCandidate::priority() const -{ - return d->priority; -} - -/// Sets the candidate's priority. -/// -/// \param priority - -void QXmppJingleCandidate::setPriority(int priority) -{ - d->priority = priority; -} - -/// Returns the candidate's protocol (e.g. "udp"). -/// - -QString QXmppJingleCandidate::protocol() const -{ - return d->protocol; -} - -/// Sets the candidate's protocol (e.g. "udp"). -/// -/// \param protocol - -void QXmppJingleCandidate::setProtocol(const QString &protocol) -{ - d->protocol = protocol; -} - -/// Returns the candidate type (e.g. "host"). -/// - -QXmppJingleCandidate::Type QXmppJingleCandidate::type() const -{ - return d->type; -} - -/// Sets the candidate type (e.g. "host"). -/// -/// \param type - -void QXmppJingleCandidate::setType(QXmppJingleCandidate::Type type) -{ - d->type = type; -} - -/// Returns true if the host address or port are empty. -/// - -bool QXmppJingleCandidate::isNull() const -{ - return d->host.isNull() || !d->port; -} - -/// \cond -void QXmppJingleCandidate::parse(const QDomElement &element) -{ - d->component = element.attribute(QStringLiteral("component")).toInt(); - d->foundation = element.attribute(QStringLiteral("foundation")); - d->generation = element.attribute(QStringLiteral("generation")).toInt(); - d->host = QHostAddress(element.attribute(QStringLiteral("ip"))); - d->id = element.attribute(QStringLiteral("id")); - d->network = element.attribute(QStringLiteral("network")).toInt(); - d->port = element.attribute(QStringLiteral("port")).toInt(); - d->priority = element.attribute(QStringLiteral("priority")).toInt(); - d->protocol = element.attribute(QStringLiteral("protocol")); - d->type = typeFromString(element.attribute(QStringLiteral("type"))); -} - -void QXmppJingleCandidate::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("candidate")); - helperToXmlAddAttribute(writer, QStringLiteral("component"), QString::number(d->component)); - helperToXmlAddAttribute(writer, QStringLiteral("foundation"), d->foundation); - helperToXmlAddAttribute(writer, QStringLiteral("generation"), QString::number(d->generation)); - helperToXmlAddAttribute(writer, QStringLiteral("id"), d->id); - helperToXmlAddAttribute(writer, QStringLiteral("ip"), d->host.toString()); - helperToXmlAddAttribute(writer, QStringLiteral("network"), QString::number(d->network)); - helperToXmlAddAttribute(writer, QStringLiteral("port"), QString::number(d->port)); - helperToXmlAddAttribute(writer, QStringLiteral("priority"), QString::number(d->priority)); - helperToXmlAddAttribute(writer, QStringLiteral("protocol"), d->protocol); - helperToXmlAddAttribute(writer, QStringLiteral("type"), typeToString(d->type)); - writer->writeEndElement(); -} - -QXmppJingleCandidate::Type QXmppJingleCandidate::typeFromString(const QString &typeStr, bool *ok) -{ - QXmppJingleCandidate::Type type; - if (typeStr == QStringLiteral("host")) { - type = HostType; - } else if (typeStr == QStringLiteral("prflx")) { - type = PeerReflexiveType; - } else if (typeStr == QStringLiteral("srflx")) { - type = ServerReflexiveType; - } else if (typeStr == QStringLiteral("relay")) { - type = RelayedType; - } else { - qWarning() << "Unknown candidate type" << typeStr; - if (ok) { - *ok = false; - } - return HostType; - } - if (ok) { - *ok = true; - } - return type; -} - -QString QXmppJingleCandidate::typeToString(QXmppJingleCandidate::Type type) -{ - QString typeStr; - switch (type) { - case HostType: - typeStr = QStringLiteral("host"); - break; - case PeerReflexiveType: - typeStr = QStringLiteral("prflx"); - break; - case ServerReflexiveType: - typeStr = QStringLiteral("srflx"); - break; - case RelayedType: - typeStr = QStringLiteral("relay"); - break; - } - return typeStr; -} -/// \endcond - -class QXmppJinglePayloadTypePrivate : public QSharedData -{ -public: - QXmppJinglePayloadTypePrivate(); - - unsigned char channels; - unsigned int clockrate; - unsigned char id; - unsigned int maxptime; - QString name; - QMap<QString, QString> parameters; - unsigned int ptime; - - // XEP-0293: Jingle RTP Feedback Negotiation - QVector<QXmppJingleRtpFeedbackProperty> rtpFeedbackProperties; - QVector<QXmppJingleRtpFeedbackInterval> rtpFeedbackIntervals; -}; - -QXmppJinglePayloadTypePrivate::QXmppJinglePayloadTypePrivate() - : channels(1), clockrate(0), id(0), maxptime(0), ptime(0) -{ -} - -QXmppJinglePayloadType::QXmppJinglePayloadType() - : d(new QXmppJinglePayloadTypePrivate()) -{ -} - -/// Constructs a copy of other. -/// -/// \param other - -QXmppJinglePayloadType::QXmppJinglePayloadType(const QXmppJinglePayloadType &other) - : d(other.d) -{ -} - -QXmppJinglePayloadType::~QXmppJinglePayloadType() -{ -} - -/// Returns the number of channels (e.g. 1 for mono, 2 for stereo). -/// - -unsigned char QXmppJinglePayloadType::channels() const -{ - return d->channels; -} - -/// Sets the number of channels (e.g. 1 for mono, 2 for stereo). -/// -/// \param channels - -void QXmppJinglePayloadType::setChannels(unsigned char channels) -{ - d->channels = channels; -} - -/// Returns the clockrate in Hz, i.e. the number of samples per second. -/// - -unsigned int QXmppJinglePayloadType::clockrate() const -{ - return d->clockrate; -} - -/// Sets the clockrate in Hz, i.e. the number of samples per second. -/// -/// \param clockrate - -void QXmppJinglePayloadType::setClockrate(unsigned int clockrate) -{ - d->clockrate = clockrate; -} - -/// Returns the payload type identifier. -/// - -unsigned char QXmppJinglePayloadType::id() const -{ - return d->id; -} - -/// Sets the payload type identifier. -/// - -void QXmppJinglePayloadType::setId(unsigned char id) -{ - Q_ASSERT(id <= 127); - d->id = id; -} - -/// Returns the maximum packet time in milliseconds. -/// - -unsigned int QXmppJinglePayloadType::maxptime() const -{ - return d->maxptime; -} - -/// Sets the maximum packet type in milliseconds. -/// -/// \param maxptime - -void QXmppJinglePayloadType::setMaxptime(unsigned int maxptime) -{ - d->maxptime = maxptime; -} - -/// Returns the payload type name. -/// - -QString QXmppJinglePayloadType::name() const -{ - return d->name; -} - -/// Sets the payload type name. -/// -/// \param name - -void QXmppJinglePayloadType::setName(const QString &name) -{ - d->name = name; -} - -/// Returns the payload parameters. - -QMap<QString, QString> QXmppJinglePayloadType::parameters() const -{ - return d->parameters; -} - -/// Sets the payload parameters. - -void QXmppJinglePayloadType::setParameters(const QMap<QString, QString> ¶meters) -{ - d->parameters = parameters; -} - -/// Returns the packet time in milliseconds (20 by default). -/// - -unsigned int QXmppJinglePayloadType::ptime() const -{ - return d->ptime ? d->ptime : 20; -} - -/// Sets the packet time in milliseconds (20 by default). -/// -/// \param ptime - -void QXmppJinglePayloadType::setPtime(unsigned int ptime) -{ - d->ptime = ptime; -} - -/// -/// Returns the properties of RTP feedback. -/// -/// \return the RTP feedback properties -/// -/// \since QXmpp 1.5 -/// -QVector<QXmppJingleRtpFeedbackProperty> QXmppJinglePayloadType::rtpFeedbackProperties() const -{ - return d->rtpFeedbackProperties; -} - -/// -/// Sets the properties of RTP feedback. -/// -/// \param rtpFeedbackProperties RTP feedback properties -/// -/// \since QXmpp 1.5 -/// -void QXmppJinglePayloadType::setRtpFeedbackProperties(const QVector<QXmppJingleRtpFeedbackProperty> &rtpFeedbackProperties) -{ - d->rtpFeedbackProperties = rtpFeedbackProperties; -} - -/// -/// Returns the intervals of RTP feedback. -/// -/// \return the RTP feedback intervals -/// -QVector<QXmppJingleRtpFeedbackInterval> QXmppJinglePayloadType::rtpFeedbackIntervals() const -{ - return d->rtpFeedbackIntervals; -} - -/// -/// Sets the intervals of RTP feedback. -/// -/// \param rtpFeedbackIntervals RTP feedback intervals -/// -void QXmppJinglePayloadType::setRtpFeedbackIntervals(const QVector<QXmppJingleRtpFeedbackInterval> &rtpFeedbackIntervals) -{ - d->rtpFeedbackIntervals = rtpFeedbackIntervals; -} - -/// \cond -void QXmppJinglePayloadType::parse(const QDomElement &element) -{ - d->id = element.attribute(QStringLiteral("id")).toInt(); - d->name = element.attribute(QStringLiteral("name")); - d->channels = element.attribute(QStringLiteral("channels")).toInt(); - if (!d->channels) { - d->channels = 1; - } - d->clockrate = element.attribute(QStringLiteral("clockrate")).toInt(); - d->maxptime = element.attribute(QStringLiteral("maxptime")).toInt(); - d->ptime = element.attribute(QStringLiteral("ptime")).toInt(); - - QDomElement child = element.firstChildElement(QStringLiteral("parameter")); - while (!child.isNull()) { - d->parameters.insert(child.attribute(QStringLiteral("name")), child.attribute(QStringLiteral("value"))); - child = child.nextSiblingElement(QStringLiteral("parameter")); - } - - parseJingleRtpFeedbackNegotiationElements(element, d->rtpFeedbackProperties, d->rtpFeedbackIntervals); -} - -void QXmppJinglePayloadType::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("payload-type")); - helperToXmlAddAttribute(writer, QStringLiteral("id"), QString::number(d->id)); - helperToXmlAddAttribute(writer, QStringLiteral("name"), d->name); - if (d->channels > 1) { - helperToXmlAddAttribute(writer, QStringLiteral("channels"), QString::number(d->channels)); - } - if (d->clockrate > 0) { - helperToXmlAddAttribute(writer, QStringLiteral("clockrate"), QString::number(d->clockrate)); - } - if (d->maxptime > 0) { - helperToXmlAddAttribute(writer, QStringLiteral("maxptime"), QString::number(d->maxptime)); - } - if (d->ptime > 0) { - helperToXmlAddAttribute(writer, QStringLiteral("ptime"), QString::number(d->ptime)); - } - - for (auto itr = d->parameters.begin(); itr != d->parameters.end(); itr++) { - writer->writeStartElement(QStringLiteral("parameter")); - writer->writeAttribute(QStringLiteral("name"), itr.key()); - writer->writeAttribute(QStringLiteral("value"), itr.value()); - writer->writeEndElement(); - } - - jingleRtpFeedbackNegotiationElementsToXml(writer, d->rtpFeedbackProperties, d->rtpFeedbackIntervals); - - writer->writeEndElement(); -} -/// \endcond - -/// Assigns the other payload type to this one. -/// -/// \param other - -QXmppJinglePayloadType &QXmppJinglePayloadType::operator=(const QXmppJinglePayloadType &other) -{ - d = other.d; - return *this; -} - -/// Returns true if this QXmppJinglePayloadType and \a other refer to the same payload type. -/// -/// \param other - -bool QXmppJinglePayloadType::operator==(const QXmppJinglePayloadType &other) const -{ - // FIXME : what to do with m_ptime and m_maxptime? - if (d->id <= 95) { - return other.d->id == d->id && other.d->clockrate == d->clockrate; - } else { - return other.d->channels == d->channels && - other.d->clockrate == d->clockrate && - other.d->name.toLower() == d->name.toLower(); - } -} - -class QXmppSdpParameterPrivate : public QSharedData -{ -public: - QString name; - QString value; -}; - -/// -/// \class QXmppSdpParameter -/// -/// \brief The QXmppSdpParameter class represents a Session Description Protocol (SDP) parameter -/// specified by RFC 4566 and used by several XEPs based on \xep{0166, Jingle}. -/// -/// \since QXmpp 1.5 -/// - -/// -/// Constructs a Session Description Protocol parameter. -/// -QXmppSdpParameter::QXmppSdpParameter() - : d(new QXmppSdpParameterPrivate()) -{ -} - -QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppSdpParameter) - -/// -/// Returns the name of the parameter. -/// -/// \return the parameter's name -/// -QString QXmppSdpParameter::name() const -{ - return d->name; -} - -/// -/// Sets the name of the parameter. -/// -/// \param name parameter's name -/// -void QXmppSdpParameter::setName(const QString &name) -{ - d->name = name; -} - -/// -/// Returns the value of the parameter. -/// -/// \return the parameter's value -/// -QString QXmppSdpParameter::value() const -{ - return d->value; -} - -/// -/// Sets the value of the parameter. -/// -/// A parameter in the form "a=b" can be created by this method. -/// Any other form of parameters can be created by not using this method. -/// The value stays a default-constructed QString then. -/// -/// \param value parameter's value -/// -void QXmppSdpParameter::setValue(const QString &value) -{ - d->value = value; -} - -/// \cond -void QXmppSdpParameter::parse(const QDomElement &element) -{ - d->name = element.attribute(QStringLiteral("name")); - d->value = element.attribute(QStringLiteral("value")); -} - -void QXmppSdpParameter::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("parameter")); - helperToXmlAddAttribute(writer, QStringLiteral("name"), d->name); - - if (!d->value.isEmpty()) { - helperToXmlAddAttribute(writer, QStringLiteral("value"), d->value); - } - - writer->writeEndElement(); -} -/// \endcond - -/// -/// Determines whether the given DOM element is a Session Description Protocol parameter element. -/// -/// \param element DOM element being checked -/// -/// \return whether element is a Session Description Protocol parameter element -/// -bool QXmppSdpParameter::isSdpParameter(const QDomElement &element) -{ - return element.tagName() == QStringLiteral("parameter"); -} - -class QXmppJingleRtpCryptoElementPrivate : public QSharedData -{ -public: - uint32_t tag = 0; - QString cryptoSuite; - QString keyParams; - QString sessionParams; -}; - -/// -/// \class QXmppJingleRtpCryptoElement -/// -/// \brief The QXmppJingleRtpCryptoElement class represents the \xep{0167: Jingle RTP Sessions} -/// "crypto" element used for SRTP negotiation. -/// -/// \since QXmpp 1.5 -/// - -/// -/// Constructs a Jingle RTP crypto element. -/// -QXmppJingleRtpCryptoElement::QXmppJingleRtpCryptoElement() - : d(new QXmppJingleRtpCryptoElementPrivate()) -{ -} - -QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpCryptoElement) - -/// -/// Returns the tag used as an identifier for the crypto element. -/// -/// \return the identifying tag -/// -uint32_t QXmppJingleRtpCryptoElement::tag() const -{ - return d->tag; -} - -/// -/// Sets the tag used as an identifier for the crypto element. -/// -/// \param tag identifying tag -/// -void QXmppJingleRtpCryptoElement::setTag(uint32_t tag) -{ - d->tag = tag; -} - -/// -/// Returns the crypto suite used as an identifier for describing the encryption and authentication -/// algorithms. -/// -/// \return the identifying crypto suite -/// -QString QXmppJingleRtpCryptoElement::cryptoSuite() const -{ - return d->cryptoSuite; -} - -/// -/// Sets the crypto suite used as an identifier for describing the encryption and authentication -/// algorithms. -/// -/// \param cryptoSuite identifying crypto suite -/// -void QXmppJingleRtpCryptoElement::setCryptoSuite(const QString &cryptoSuite) -{ - d->cryptoSuite = cryptoSuite; -} - -/// -/// Returns the key parameters providing one or more sets of keying material for the crypto suite. -/// -/// \return the key parameters providing one or more sets of keying material -/// -QString QXmppJingleRtpCryptoElement::keyParams() const -{ - return d->keyParams; -} - -/// -/// Sets the key parameters providing one or more sets of keying material for the crypto suite. -/// -/// \param keyParams key parameters providing one or more sets of keying material -/// -void QXmppJingleRtpCryptoElement::setKeyParams(const QString &keyParams) -{ - d->keyParams = keyParams; -} - -/// -/// Returns the session parameters providing transport-specific data. -/// -/// \return the session parameters providing transport-specific data -/// -QString QXmppJingleRtpCryptoElement::sessionParams() const -{ - return d->sessionParams; -} - -/// -/// Sets the session parameters providing transport-specific data. -/// -/// \param sessionParams session parameters providing transport-specific data -/// -void QXmppJingleRtpCryptoElement::setSessionParams(const QString &sessionParams) -{ - d->sessionParams = sessionParams; -} - -/// \cond -void QXmppJingleRtpCryptoElement::parse(const QDomElement &element) -{ - d->tag = element.attribute(QStringLiteral("tag")).toUInt(); - d->cryptoSuite = element.attribute(QStringLiteral("crypto-suite")); - d->keyParams = element.attribute(QStringLiteral("key-params")); - d->sessionParams = element.attribute(QStringLiteral("session-params")); -} - -void QXmppJingleRtpCryptoElement::toXml(QXmlStreamWriter *writer) const -{ - if (!d->cryptoSuite.isEmpty() && !d->keyParams.isEmpty()) { - writer->writeStartElement(QStringLiteral("crypto")); - writer->writeAttribute(QStringLiteral("tag"), QString::number(d->tag)); - writer->writeAttribute(QStringLiteral("crypto-suite"), d->cryptoSuite); - writer->writeAttribute(QStringLiteral("key-params"), d->keyParams); - helperToXmlAddAttribute(writer, QStringLiteral("session-params"), d->sessionParams); - writer->writeEndElement(); - } -} -/// \endcond - -/// -/// Determines whether the given DOM element is an RTP crypto element. -/// -/// \param element DOM element being checked -/// -/// \return whether element is an RTP crypto element -/// -bool QXmppJingleRtpCryptoElement::isJingleRtpCryptoElement(const QDomElement &element) -{ - return element.tagName() == QStringLiteral("crypto"); -} - -class QXmppJingleRtpEncryptionPrivate : public QSharedData -{ -public: - bool isRequired = false; - QVector<QXmppJingleRtpCryptoElement> cryptoElements; -}; - -/// -/// \class QXmppJingleRtpEncryption -/// -/// \brief The QXmppJingleRtpEncryption class represents the \xep{0167: Jingle RTP Sessions} -/// "encryption" element used for SRTP negotiation. -/// -/// \since QXmpp 1.5 -/// - -/// -/// Constructs a Jingle RTP encryption. -/// -QXmppJingleRtpEncryption::QXmppJingleRtpEncryption() - : d(new QXmppJingleRtpEncryptionPrivate()) -{ -} - -QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpEncryption) - -/// -/// Returns whether encryption via SRTP is required. -/// -/// \return whether encryption is required -/// -bool QXmppJingleRtpEncryption::isRequired() const -{ - return d->isRequired; -} - -/// -/// Sets whether encryption via SRTP is required. -/// -/// \param isRequired whether encryption is required -/// -void QXmppJingleRtpEncryption::setRequired(bool isRequired) -{ - d->isRequired = isRequired; -} - -/// -/// Returns the crypto elements used for encryption via SRTP. -/// -/// \return the crypto elements -/// -QVector<QXmppJingleRtpCryptoElement> QXmppJingleRtpEncryption::cryptoElements() const -{ - return d->cryptoElements; -} - -/// -/// Sets the crypto elements used for encryption via SRTP. -/// -/// \param cryptoElements the crypto elements -/// -void QXmppJingleRtpEncryption::setCryptoElements(const QVector<QXmppJingleRtpCryptoElement> &cryptoElements) -{ - d->cryptoElements = cryptoElements; -} - -/// \cond -void QXmppJingleRtpEncryption::parse(const QDomElement &element) -{ - d->isRequired = element.attribute(QStringLiteral("required")) == QStringLiteral("true") || - element.attribute(QStringLiteral("required")) == QStringLiteral("1"); - - for (auto childElement = element.firstChildElement(); - !childElement.isNull(); - childElement = childElement.nextSiblingElement()) { - if (QXmppJingleRtpCryptoElement::isJingleRtpCryptoElement(childElement)) { - QXmppJingleRtpCryptoElement cryptoElement; - cryptoElement.parse(childElement); - d->cryptoElements.append(std::move(cryptoElement)); - } - } -} - -void QXmppJingleRtpEncryption::toXml(QXmlStreamWriter *writer) const -{ - if (!d->cryptoElements.isEmpty()) { - writer->writeStartElement(QStringLiteral("encryption")); - writer->writeDefaultNamespace(ns_jingle_rtp); - - if (d->isRequired) { - writer->writeAttribute(QStringLiteral("required"), QStringLiteral("1")); - } - - for (const auto &cryptoElement : std::as_const(d->cryptoElements)) { - cryptoElement.toXml(writer); - } - - writer->writeEndElement(); - } -} -/// \endcond - -/// -/// Determines whether the given DOM element is an RTP encryption element. -/// -/// \param element DOM element being checked -/// -/// \return whether element is an RTP encryption element -/// -bool QXmppJingleRtpEncryption::isJingleRtpEncryption(const QDomElement &element) -{ - return element.tagName() == QStringLiteral("encryption") && - element.namespaceURI() == ns_jingle_rtp; -} - -class QXmppJingleRtpFeedbackPropertyPrivate : public QSharedData -{ -public: - QString type; - QString subtype; - QVector<QXmppSdpParameter> parameters; -}; - -/// -/// \class QXmppJingleRtpFeedbackProperty -/// -/// \brief The QXmppJingleRtpFeedbackProperty class represents the -/// \xep{0293, Jingle RTP Feedback Negotiation} "rtcp-fb" element. -/// -/// \since QXmpp 1.5 -/// - -/// -/// Constructs a Jingle RTP feedback property. -/// -QXmppJingleRtpFeedbackProperty::QXmppJingleRtpFeedbackProperty() - : d(new QXmppJingleRtpFeedbackPropertyPrivate()) -{ -} - -QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpFeedbackProperty) - -/// -/// Returns the type of RTP feedback. -/// -/// \return the RTP feedback type -/// -QString QXmppJingleRtpFeedbackProperty::type() const -{ - return d->type; -} - -/// -/// Sets the type of RTP feedback. -/// -/// \param type RTP feedback type -/// -void QXmppJingleRtpFeedbackProperty::setType(const QString &type) -{ - d->type = type; -} - -/// -/// Returns the subtype for RTP feedback. -/// -/// \return the RTP feedback subtype -/// -QString QXmppJingleRtpFeedbackProperty::subtype() const -{ - return d->subtype; -} - -/// -/// Sets the subtype of RTP feedback. -/// -/// If there is more than one parameter, use QXmppJingleRtpFeedbackProperty::setParameters() -/// instead of this method. -/// -/// \param subtype RTP feedback subtype -/// -void QXmppJingleRtpFeedbackProperty::setSubtype(const QString &subtype) -{ - d->subtype = subtype; -} - -/// -/// Returns the parameters of RTP feedback. -/// -/// \return the RTP feedback parameters -/// -QVector<QXmppSdpParameter> QXmppJingleRtpFeedbackProperty::parameters() const -{ - return d->parameters; -} - -/// -/// Sets the parameters of RTP feedback. -/// -/// Additional parameters can be set by this method. -/// If there is only one parameter, use QXmppJingleRtpFeedbackProperty::setSubtype() -/// instead of this method. -/// -/// \param parameters RTP feedback parameters -/// -void QXmppJingleRtpFeedbackProperty::setParameters(const QVector<QXmppSdpParameter> ¶meters) -{ - d->parameters = parameters; -} - -/// \cond -void QXmppJingleRtpFeedbackProperty::parse(const QDomElement &element) -{ - d->type = element.attribute(QStringLiteral("type")); - d->subtype = element.attribute(QStringLiteral("subtype")); - parseSdpParameters(element, d->parameters); -} - -void QXmppJingleRtpFeedbackProperty::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("rtcp-fb")); - writer->writeDefaultNamespace(ns_jingle_rtp_feedback_negotiation); - helperToXmlAddAttribute(writer, QStringLiteral("type"), d->type); - - // If there are parameters, they must be used instead of the subtype. - if (d->subtype.isEmpty()) { - sdpParametersToXml(writer, d->parameters); - } else { - helperToXmlAddAttribute(writer, QStringLiteral("subtype"), d->subtype); - } - - writer->writeEndElement(); -} -/// \endcond - -/// -/// Determines whether the given DOM element is an RTP feedback property element. -/// -/// \param element DOM element being checked -/// -/// \return whether element is an RTP feedback property element -/// -bool QXmppJingleRtpFeedbackProperty::isJingleRtpFeedbackProperty(const QDomElement &element) -{ - return element.tagName() == QStringLiteral("rtcp-fb") && - element.namespaceURI() == ns_jingle_rtp_feedback_negotiation; -} - -/// -/// \class QXmppJingleRtpFeedbackInterval -/// -/// \brief The QXmppJingleRtpFeedbackInterval class represents the -/// \xep{0293, Jingle RTP Feedback Negotiation} "rtcp-fb-trr-int" element. -/// -/// \since QXmpp 1.5 -/// - -/// -/// Constructs a Jingle RTP feedback interval. -/// -QXmppJingleRtpFeedbackInterval::QXmppJingleRtpFeedbackInterval() -{ -} - -QXMPP_PRIVATE_DEFINE_RULE_OF_SIX(QXmppJingleRtpFeedbackInterval) - -/// -/// Returns the value of the RTP feedback interval. -/// -/// \return the RTP feedback interval value -/// -uint64_t QXmppJingleRtpFeedbackInterval::value() const -{ - return m_value; -} - -/// -/// Sets the value of the RTP feedback interval. -/// -/// \param value RTP feedback interval value -/// -void QXmppJingleRtpFeedbackInterval::setValue(uint64_t value) -{ - m_value = value; -} - -/// \cond -void QXmppJingleRtpFeedbackInterval::parse(const QDomElement &element) -{ - m_value = element.attribute(QStringLiteral("value")).toUInt(); -} - -void QXmppJingleRtpFeedbackInterval::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement(QStringLiteral("rtcp-fb-trr-int")); - writer->writeDefaultNamespace(ns_jingle_rtp_feedback_negotiation); - helperToXmlAddAttribute(writer, QStringLiteral("value"), QString::number(m_value)); - writer->writeEndElement(); -} -/// \endcond - -/// -/// Determines whether the given DOM element is an RTP feedback interval element. -/// -/// \param element DOM element being checked -/// -/// \return whether element is an RTP feedback interval element -/// -bool QXmppJingleRtpFeedbackInterval::isJingleRtpFeedbackInterval(const QDomElement &element) -{ - 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; -} |
