diff options
| author | Melvin Keskin <melvo@olomono.de> | 2022-10-01 18:07:16 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-01 18:07:16 +0200 |
| commit | 58dfd25a6477fda887e8040e174190eb7929381d (patch) | |
| tree | 365ace4d90b893d0fe85ded465b2f601b4a3574d /src | |
| parent | d757ce3bf70058a7b4a0570b6b440de30b692b21 (diff) | |
| download | qxmpp-58dfd25a6477fda887e8040e174190eb7929381d.tar.gz | |
Implement XEP-0167: Jingle RTP Sessions Informational Messages (#460)
Diffstat (limited to 'src')
| -rw-r--r-- | src/base/QXmppJingleIq.cpp | 185 | ||||
| -rw-r--r-- | src/base/QXmppJingleIq.h | 46 | ||||
| -rw-r--r-- | src/client/QXmppCallManager.cpp | 3 |
3 files changed, 217 insertions, 17 deletions
diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp index 36336f48..32d9549e 100644 --- a/src/base/QXmppJingleIq.cpp +++ b/src/base/QXmppJingleIq.cpp @@ -188,6 +188,64 @@ QXmppJingleIqContentPrivate::QXmppJingleIqContentPrivate() { } +/// +/// \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()) @@ -849,11 +907,12 @@ public: QList<QXmppJingleIq::Content> contents; QXmppJingleIq::Reason reason; - bool ringing; + + std::optional<QXmppJingleIq::RtpSessionState> rtpSessionState; }; QXmppJingleIqPrivate::QXmppJingleIqPrivate() - : action(QXmppJingleIq::ContentAccept), ringing(false) + : action(QXmppJingleIq::ContentAccept) { } @@ -968,24 +1027,39 @@ 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 { - return d->ringing; + 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) { - d->ringing = ringing; + if (ringing) { + d->rtpSessionState = RtpSessionStateRinging(); + } else { + d->rtpSessionState = std::nullopt; + } } /// Returns the session ID. - QString QXmppJingleIq::sid() const { return d->sid; @@ -1024,6 +1098,36 @@ 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) { @@ -1055,7 +1159,7 @@ void QXmppJingleIq::parseElementFromChild(const QDomElement &element) d->contents.clear(); QDomElement contentElement = jingleElement.firstChildElement(QStringLiteral("content")); while (!contentElement.isNull()) { - QXmppJingleIq::Content content; + Content content; content.parse(contentElement); addContent(content); contentElement = contentElement.nextSiblingElement(QStringLiteral("content")); @@ -1063,9 +1167,36 @@ void QXmppJingleIq::parseElementFromChild(const QDomElement &element) QDomElement reasonElement = jingleElement.firstChildElement(QStringLiteral("reason")); d->reason.parse(reasonElement); - // ringing - QDomElement ringingElement = jingleElement.firstChildElement(QStringLiteral("ringing")); - d->ringing = (ringingElement.namespaceURI() == ns_jingle_rtp_info); + 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 @@ -1091,10 +1222,36 @@ void QXmppJingleIq::toXmlElementFromChild(QXmlStreamWriter *writer) const d->reason.toXml(writer); - // ringing - if (d->ringing) { - writer->writeStartElement(QStringLiteral("ringing")); + 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(); } diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h index 61b16461..02ecc9a5 100644 --- a/src/base/QXmppJingleIq.h +++ b/src/base/QXmppJingleIq.h @@ -8,6 +8,8 @@ #include "QXmppIq.h" +#include <variant> + #include <QHostAddress> class QXmppJingleCandidatePrivate; @@ -237,6 +239,42 @@ public: TransportReplace }; + enum Creator { + /// The initiator generated the content type. + Initiator, + /// The responder generated the content type. + Responder + }; + + struct RtpSessionStateActive + { + }; + + struct RtpSessionStateHold + { + }; + + struct RtpSessionStateUnhold + { + }; + + struct RtpSessionStateMuting + { + /// True when temporarily not sending media to the other party but continuing to accept + /// media from it, false for ending mute state + bool isMute = true; + /// Creator of the corresponding session + Creator creator; + /// Session to be muted (e.g., only audio or video) + QString name; + }; + + struct RtpSessionStateRinging + { + }; + + using RtpSessionState = std::variant<RtpSessionStateActive, RtpSessionStateHold, RtpSessionStateUnhold, RtpSessionStateMuting, RtpSessionStateRinging>; + /// \internal /// /// The QXmppJingleIq::Content class represents the "content" element of a @@ -386,9 +424,12 @@ public: QString responder() const; void setResponder(const QString &responder); - // XEP-0167: Jingle RTP Sessions +#if QXMPP_DEPRECATED_SINCE(1, 5) + QT_DEPRECATED_X("Use QXmpp::rtpSessionState() instead") bool ringing() const; + QT_DEPRECATED_X("Use QXmpp::setRtpSessionState() instead") void setRinging(bool ringing); +#endif QString sid() const; void setSid(const QString &sid); @@ -396,6 +437,9 @@ public: QString mujiGroupChatJid() const; void setMujiGroupChatJid(const QString &mujiGroupChatJid); + std::optional<RtpSessionState> rtpSessionState() const; + void setRtpSessionState(const std::optional<RtpSessionState> &rtpSessionState); + /// \cond static bool isJingleIq(const QDomElement &element); /// \endcond diff --git a/src/client/QXmppCallManager.cpp b/src/client/QXmppCallManager.cpp index 807e09ad..5a2065a9 100644 --- a/src/client/QXmppCallManager.cpp +++ b/src/client/QXmppCallManager.cpp @@ -281,9 +281,8 @@ void QXmppCallManager::_q_jingleIqReceived(const QXmppJingleIq &iq) QXmppJingleIq ringing; ringing.setTo(call->jid()); ringing.setType(QXmppIq::Set); - ringing.setAction(QXmppJingleIq::SessionInfo); ringing.setSid(call->sid()); - ringing.setRinging(true); + ringing.setRtpSessionState(QXmppJingleIq::RtpSessionStateRinging()); call->d->sendRequest(ringing); // notify user |
