From 26bea26e6d0bbac7cc9d9835eac9495baa3d1a5e Mon Sep 17 00:00:00 2001 From: Lars Toenning Date: Sun, 10 Mar 2024 16:48:23 +0100 Subject: [PATCH] feat: Add support for FSD mute packet Fixes #254 --- src/blackcore/CMakeLists.txt | 2 + src/blackcore/afv/clients/afvclient.cpp | 30 +++++++++++- src/blackcore/afv/clients/afvclient.h | 5 ++ src/blackcore/context/contextnetwork.h | 3 ++ src/blackcore/context/contextnetworkimpl.cpp | 1 + src/blackcore/fsd/fsdclient.cpp | 10 ++++ src/blackcore/fsd/fsdclient.h | 2 + src/blackcore/fsd/messagebase.h | 1 + src/blackcore/fsd/mute.cpp | 33 +++++++++++++ src/blackcore/fsd/mute.h | 50 ++++++++++++++++++++ 10 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/blackcore/fsd/mute.cpp create mode 100644 src/blackcore/fsd/mute.h diff --git a/src/blackcore/CMakeLists.txt b/src/blackcore/CMakeLists.txt index b8a48f362..ee871b83a 100644 --- a/src/blackcore/CMakeLists.txt +++ b/src/blackcore/CMakeLists.txt @@ -152,6 +152,8 @@ add_library(core SHARED fsd/pilotdataupdate.cpp fsd/ping.cpp fsd/messagebase.cpp + fsd/mute.cpp + fsd/mute.h fsd/enums.h fsd/deleteatc.h fsd/clientidentification.h diff --git a/src/blackcore/afv/clients/afvclient.cpp b/src/blackcore/afv/clients/afvclient.cpp index cf3707d0a..4592d9540 100644 --- a/src/blackcore/afv/clients/afvclient.cpp +++ b/src/blackcore/afv/clients/afvclient.cpp @@ -114,9 +114,17 @@ namespace BlackCore::Afv::Clients { if (m_connectedWithContext) { return; } if (!hasContexts()) { return; } - this->disconnect(sApp->getIContextOwnAircraft()); - sApp->getIContextOwnAircraft()->disconnect(this); + + // Disconnect all previously connect signals between the AfvClient and the required contexts + for (auto context : QVector { sApp->getIContextOwnAircraft(), sApp->getIContextNetwork() }) + { + this->disconnect(context); + context->disconnect(this); + } + connect(sApp->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CAfvClient::onUpdateTransceiversFromContext, Qt::QueuedConnection); + connect(sApp->getIContextNetwork(), &IContextNetwork::muteRequestReceived, this, &CAfvClient::toggleTransmissionCapability, Qt::QueuedConnection); + m_connectedWithContext = true; } @@ -678,6 +686,12 @@ namespace BlackCore::Afv::Clients return; } + if (active && m_disableTransmissionCapability) + { + // Block transmissions + return; + } + if (m_transmit == active) { return; } m_transmit = active; @@ -1305,6 +1319,18 @@ namespace BlackCore::Afv::Clients }); } + void CAfvClient::toggleTransmissionCapability(bool disableTransmission) + { + if (m_disableTransmissionCapability == disableTransmission) { return; } + m_disableTransmissionCapability = disableTransmission; + + if (disableTransmission) + { + // Stop current transmissions + setPtt(false); + } + } + QVector CAfvClient::getAliasedStations() const { QMutexLocker lock(&m_mutex); diff --git a/src/blackcore/afv/clients/afvclient.h b/src/blackcore/afv/clients/afvclient.h index 78ecb9914..8c44fce74 100644 --- a/src/blackcore/afv/clients/afvclient.h +++ b/src/blackcore/afv/clients/afvclient.h @@ -339,6 +339,10 @@ namespace BlackCore::Afv::Clients //! Connect again in given ms void reconnectTo(const QString &cid, const QString &password, const QString &callsign, const QString &client, int delayMs, const BlackMisc::CStatusMessage &msg); + //! Toggle (enable/disable) the transmission capability. + //! This is triggered by the #MU FSD packet to mute the user remotely. + void toggleTransmissionCapability(bool disableTransmission); + //! @{ //! All aliased stations //! \threadsafe @@ -385,6 +389,7 @@ namespace BlackCore::Afv::Clients std::atomic_bool m_transmit { false }; std::atomic_bool m_transmitHistory { false }; + std::atomic_bool m_disableTransmissionCapability { false }; //!< whether the user should be unable to transmit QVector m_transmittingTransceivers; QVector m_transceivers; QSet m_enabledTransceivers; diff --git a/src/blackcore/context/contextnetwork.h b/src/blackcore/context/contextnetwork.h index 2a9d8d4a2..c53c90cb2 100644 --- a/src/blackcore/context/contextnetwork.h +++ b/src/blackcore/context/contextnetwork.h @@ -145,6 +145,9 @@ namespace BlackCore::Context //! Network error void severeNetworkError(const QString &errorMessage); + //! Mute request received + void muteRequestReceived(bool mute); + //! Connection status changed //! \sa IContextNetwork::connectedServerChanged void connectionStatusChanged(const BlackMisc::Network::CConnectionStatus &from, const BlackMisc::Network::CConnectionStatus &to); diff --git a/src/blackcore/context/contextnetworkimpl.cpp b/src/blackcore/context/contextnetworkimpl.cpp index e7b78a7a7..aa1e0d0ed 100644 --- a/src/blackcore/context/contextnetworkimpl.cpp +++ b/src/blackcore/context/contextnetworkimpl.cpp @@ -69,6 +69,7 @@ namespace BlackCore::Context connect(m_fsdClient, &CFSDClient::textMessagesReceived, this, &CContextNetwork::onTextMessagesReceived, Qt::QueuedConnection); connect(m_fsdClient, &CFSDClient::textMessageSent, this, &CContextNetwork::onTextMessageSent, Qt::QueuedConnection); connect(m_fsdClient, &CFSDClient::severeNetworkError, this, &CContextNetwork::severeNetworkError, Qt::QueuedConnection); + connect(m_fsdClient, &CFSDClient::muteRequestReceived, this, &CContextNetwork::muteRequestReceived, Qt::QueuedConnection); // 2. Update timer for data (network data such as frequency) // we use 2 timers so we can query at different times (not too many queirs at once) diff --git a/src/blackcore/fsd/fsdclient.cpp b/src/blackcore/fsd/fsdclient.cpp index 839c947b9..49949749e 100644 --- a/src/blackcore/fsd/fsdclient.cpp +++ b/src/blackcore/fsd/fsdclient.cpp @@ -35,6 +35,7 @@ #include "blackcore/fsd/planeinformationfsinn.h" #include "blackcore/fsd/revbclientparts.h" #include "blackcore/fsd/rehost.h" +#include "blackcore/fsd/mute.h" #include "blackmisc/aviation/flightplan.h" #include "blackmisc/network/rawfsdmessage.h" @@ -1086,6 +1087,7 @@ namespace BlackCore::Fsd m_messageTypeMapping["#TM"] = MessageType::TextMessage; m_messageTypeMapping["#SB"] = MessageType::PilotClientCom; m_messageTypeMapping["$XX"] = MessageType::Rehost; + m_messageTypeMapping["#MU"] = MessageType::Mute; // Euroscope m_messageTypeMapping["SIMDATA"] = MessageType::EuroscopeSimData; @@ -1664,6 +1666,13 @@ namespace BlackCore::Fsd initiateConnection(rehostingSocket, rehost.m_hostname); } + void CFSDClient::handleMute(const QStringList &tokens) + { + const Mute mute = Mute::fromTokens(tokens); + if (mute.receiver() != m_ownCallsign.asString()) { return; } + emit muteRequestReceived(mute.m_mute); + } + void CFSDClient::initiateConnection(std::shared_ptr rehostingSocket, const QString &rehostingHost) { const CServer server = this->getServer(); @@ -2306,6 +2315,7 @@ namespace BlackCore::Fsd case MessageType::VisualPilotDataToggle: handleVisualPilotDataToggle(tokens); break; case MessageType::EuroscopeSimData: handleEuroscopeSimData(tokens); break; case MessageType::Rehost: handleRehost(tokens); break; + case MessageType::Mute: handleMute(tokens); break; // normally we should not get here default: diff --git a/src/blackcore/fsd/fsdclient.h b/src/blackcore/fsd/fsdclient.h index aae30686b..728db119e 100644 --- a/src/blackcore/fsd/fsdclient.h +++ b/src/blackcore/fsd/fsdclient.h @@ -291,6 +291,7 @@ namespace BlackCore::Fsd void rawFsdMessage(const BlackMisc::Network::CRawFsdMessage &rawFsdMessage); void planeInformationFsinnReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &airlineIcaoDesignator, const QString &aircraftDesignator, const QString &combinedAircraftType, const QString &modelString); void revbAircraftConfigReceived(const QString &sender, const QString &config, qint64 currentOffsetTimeMs); + void muteRequestReceived(bool mute); //! @} @@ -442,6 +443,7 @@ namespace BlackCore::Fsd void handleFsdIdentification(const QStringList &tokens); void handleRevBClientPartsPacket(const QStringList &tokens); void handleRehost(const QStringList &tokens); + void handleMute(const QStringList &tokens); // void handleUnknownPacket(const QString &line); diff --git a/src/blackcore/fsd/messagebase.h b/src/blackcore/fsd/messagebase.h index 4ec1cb8c1..08b161728 100644 --- a/src/blackcore/fsd/messagebase.h +++ b/src/blackcore/fsd/messagebase.h @@ -48,6 +48,7 @@ enum class MessageType RevBClientParts, // IVAO only RevBPilotDescription, // -PD IVAO only not handled in swift Rehost, + Mute, }; namespace BlackCore::Fsd diff --git a/src/blackcore/fsd/mute.cpp b/src/blackcore/fsd/mute.cpp new file mode 100644 index 000000000..d52fb52b5 --- /dev/null +++ b/src/blackcore/fsd/mute.cpp @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +#include "blackcore/fsd/mute.h" + +#include "blackmisc/logmessage.h" + +namespace BlackCore::Fsd +{ + Mute::Mute(const QString &sender, const QString &receiver, bool mute) + : MessageBase(sender, receiver), + m_mute(mute) + {} + + QStringList Mute::toTokens() const + { + QStringList tokens; + tokens.push_back(m_sender); + tokens.push_back(m_receiver); + tokens.push_back(QString::number(m_mute ? 1 : 0)); + return tokens; + } + + Mute Mute::fromTokens(const QStringList &tokens) + { + if (tokens.size() < 3) + { + BlackMisc::CLogMessage(static_cast(nullptr)).debug(u"Wrong number of arguments."); + return {}; + }; + return Mute(tokens[0], tokens[1], tokens[2] == QStringLiteral("1")); + } +} diff --git a/src/blackcore/fsd/mute.h b/src/blackcore/fsd/mute.h new file mode 100644 index 000000000..463f93fe3 --- /dev/null +++ b/src/blackcore/fsd/mute.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright (C) swift Project Community / Contributors +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1 + +//! \file + +#ifndef BLACKCORE_FSD_MUTE_H +#define BLACKCORE_FSD_MUTE_H + +#include "blackcore/fsd/messagebase.h" + +namespace BlackCore::Fsd +{ + //! Mute the user for AFV + class BLACKCORE_EXPORT Mute : public MessageBase + { + public: + //! Constructor + Mute(const QString &sender, const QString &receiver, bool mute); + + //! Message converted to tokens + QStringList toTokens() const; + + //! Construct from tokens + static Mute fromTokens(const QStringList &tokens); + + //! PDU identifier + static QString pdu() { return "#MU"; } + + bool m_mute = false; //!< Flag whether the user should be muted/unmuted + + private: + Mute() = default; + }; + + //! Equal to operator + inline bool operator==(const Mute &lhs, const Mute &rhs) + { + return lhs.sender() == rhs.sender() && + lhs.receiver() == rhs.receiver() && + lhs.m_mute == rhs.m_mute; + } + + //! Not equal to operator + inline bool operator!=(const Mute &lhs, const Mute &rhs) + { + return !(lhs == rhs); + } +} + +#endif // guard