diff options
author | Robert Adam <dev@robert-adam.de> | 2020-03-25 21:28:54 +0300 |
---|---|---|
committer | Robert Adam <dev@robert-adam.de> | 2020-04-16 10:29:49 +0300 |
commit | 8aadee917dea7a256b283585d14e1d0f0080fe27 (patch) | |
tree | c2282077f09b1083535ea1ed07439c52288b33d8 /src/murmur/Messages.cpp | |
parent | dcd5842008ff3123484edffc84d619a559824334 (diff) |
Feature: Channel Listeners
This implements #3319 by allowing users to "listen" to a channel they
have not joined. Doing so will place a "listener proxy" (in other
software this is sometimes known as a "phantom") in that channel which
will look like a normal user except that it'll have the same name as the
user listening to that channel and an ear-icon instead of the normal
avatar-icon. It will also always show a muted-icon next to it.
If a listener proxy is in a channel, the server will route all audio
packets from that channel to the user the proxy belongs to (as if that
user was in the channel). Note though that the opposite of this is not
true: The users in the channel will not hear audio from the listening
user unless that user decides to join the channel.
Furthermore it is possible to set a local volume adjustment for each
individual proxy that will be applied to all audio that is received
through it.
Diffstat (limited to 'src/murmur/Messages.cpp')
-rw-r--r-- | src/murmur/Messages.cpp | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index 9451d78ee..625e95033 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -15,6 +15,7 @@ #include "Version.h" #include "CryptState.h" #include "Meta.h" +#include "ChannelListener.h" #include <QtCore/QStack> #include <QtCore/QtEndian> @@ -460,6 +461,10 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg if (! u->qsHash.isEmpty()) mpus.set_hash(u8(u->qsHash)); + foreach(int channelID, ChannelListener::getListenedChannelsForUser(u)) { + mpus.add_listening_channel_add(channelID); + } + sendMessage(uSource, mpus); } @@ -651,6 +656,40 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { } } + QList<Channel *> listeningChannelsAdd; + int passedChannelListener = 0; + // Check permission for each channel + for (int i = 0; i < msg.listening_channel_add_size(); i++) { + Channel *c = qhChannels.value(msg.listening_channel_add(i)); + + if (!c) { + continue; + } + + if (!hasPermission(uSource, c, ChanACL::Listen)) { + PERM_DENIED(uSource, c, ChanACL::Listen); + continue; + } + + if (Meta::mp.iMaxListenersPerChannel >= 0 + && Meta::mp.iMaxListenersPerChannel - ChannelListener::getListenerCountForChannel(c) - 1 < 0) { + // A limit for the amount of listener proxies per channel is set and it has been reached already + PERM_DENIED_FALLBACK(ChannelListenerLimit, 0x010400, QLatin1String("No more listeners allowed in this channel")); + continue; + } + + if (Meta::mp.iMaxListenerProxiesPerUser >= 0 + && Meta::mp.iMaxListenerProxiesPerUser - ChannelListener::getListenedChannelCountForUser(uSource) - passedChannelListener - 1 < 0) { + // A limit for the amount of listener proxies per user is set and it has been reached already + PERM_DENIED_FALLBACK(UserListenerLimit, 0x010400, QLatin1String("No more listeners allowed in this channel")); + continue; + } + + passedChannelListener++; + + listeningChannelsAdd << c; + } + if (msg.has_mute() || msg.has_deaf() || msg.has_suppress() || msg.has_priority_speaker()) { if (pDstServerUser->iId == 0) { PERM_DENIED_TYPE(SuperUser); @@ -722,7 +761,8 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { } // Prevent self-targeting state changes from being applied to others - if ((pDstServerUser != uSource) && (msg.has_self_deaf() || msg.has_self_mute() || msg.has_plugin_context() || msg.has_plugin_identity() || msg.has_recording())) { + if ((pDstServerUser != uSource) && (msg.has_self_deaf() || msg.has_self_mute() || msg.has_plugin_context() || msg.has_plugin_identity() + || msg.has_recording() || msg.listening_channel_add_size() > 0 || msg.listening_channel_remove_size() > 0)) { return; } @@ -848,7 +888,33 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { userEnterChannel(pDstServerUser, c, msg); log(uSource, QString("Moved %1 to %2").arg(QString(*pDstServerUser), QString(*c))); bBroadcast = true; + + if (ChannelListener::isListening(pDstServerUser, c)) { + // If a user joins a channel (s)he has been listening to before, it means that this user will no + // longer listen into that channel (as joining it can be viewed as promoting the listening to a join) + msg.add_listening_channel_remove(c->iId); + } + } + + // Handle channel listening + // Note that it is important to handle the listening channels after channel-joins + foreach(Channel *c, listeningChannelsAdd) { + ChannelListener::addListener(uSource, c); + + log(QString::fromLatin1("\"%1\" is now listening to channel \"%2\"").arg(QString(*uSource)).arg(QString(*c))); } + for (int i = 0; i < msg.listening_channel_remove_size(); i++) { + Channel *c = qhChannels.value(msg.listening_channel_remove(i)); + + if (c) { + ChannelListener::removeListener(uSource, c); + + log(QString::fromLatin1("\"%1\" is no longer listening to \"%2\"").arg(QString(*uSource)).arg(QString(*c))); + } + } + + bBroadcast = bBroadcast || !listeningChannelsAdd.isEmpty() || msg.listening_channel_remove_size() > 0; + bool bDstAclChanged = false; if (msg.has_user_id()) { |