aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelvin Keskin <melvo@olomono.de>2022-10-01 18:07:16 +0200
committerGitHub <noreply@github.com>2022-10-01 18:07:16 +0200
commit58dfd25a6477fda887e8040e174190eb7929381d (patch)
tree365ace4d90b893d0fe85ded465b2f601b4a3574d /src
parentd757ce3bf70058a7b4a0570b6b440de30b692b21 (diff)
downloadqxmpp-58dfd25a6477fda887e8040e174190eb7929381d.tar.gz
Implement XEP-0167: Jingle RTP Sessions Informational Messages (#460)
Diffstat (limited to 'src')
-rw-r--r--src/base/QXmppJingleIq.cpp185
-rw-r--r--src/base/QXmppJingleIq.h46
-rw-r--r--src/client/QXmppCallManager.cpp3
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