Merge PR #5003: FIX(server): ChannelListener IDs colliding across VServers

As the ChannelListener feature was implemented via a Singleton class,
there was only ever a single, global instance keeping track of listeners.
If however there were multiple VServers running from within a single
Mumble server instance, all of them would use the same ChannelListener
instance. That allowed for user-IDs to collide across different VServers
when it came to listener-management.

Thus listeners could appear/disappear seemingly at random whenever a
user on a different VServer (with the same session ID on that server)
changed their listeners.

Fixes #4366
This commit is contained in:
Robert Adam 2021-05-16 17:33:51 +02:00 committed by GitHub
commit 05db5fe6fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 354 additions and 591 deletions

View File

@ -1,275 +0,0 @@
// Copyright 2020-2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "ChannelListener.h"
#include "Channel.h"
#include "User.h"
#ifdef MUMBLE
# include "ServerHandler.h"
# include "Database.h"
# include "Global.h"
#endif
#include <QtCore/QReadLocker>
#include <QtCore/QWriteLocker>
// init static instance
ChannelListener ChannelListener::s_instance;
ChannelListener::ChannelListener()
: QObject(nullptr), m_listenerLock(), m_listeningUsers(), m_listenedChannels()
#ifdef MUMBLE
,
m_volumeLock(), m_listenerVolumeAdjustments(), m_initialSyncDone(false)
#endif
{
}
void ChannelListener::addListenerImpl(unsigned int userSession, int channelID) {
QWriteLocker lock(&m_listenerLock);
m_listeningUsers[userSession] << channelID;
m_listenedChannels[channelID] << userSession;
}
void ChannelListener::removeListenerImpl(unsigned int userSession, int channelID) {
QWriteLocker lock(&m_listenerLock);
m_listeningUsers[userSession].remove(channelID);
m_listenedChannels[channelID].remove(userSession);
}
bool ChannelListener::isListeningImpl(unsigned int userSession, int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID].contains(userSession);
}
bool ChannelListener::isListeningToAnyImpl(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return !m_listeningUsers[userSession].isEmpty();
}
bool ChannelListener::isListenedByAnyImpl(int channelID) const {
QReadLocker lock(&m_listenerLock);
return !m_listenedChannels[channelID].isEmpty();
}
const QSet< unsigned int > ChannelListener::getListenersForChannelImpl(int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID];
}
const QSet< int > ChannelListener::getListenedChannelsForUserImpl(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return m_listeningUsers[userSession];
}
int ChannelListener::getListenerCountForChannelImpl(int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID].size();
}
int ChannelListener::getListenedChannelCountForUserImpl(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return m_listeningUsers[userSession].size();
}
#ifdef MUMBLE
void ChannelListener::setListenerLocalVolumeAdjustmentImpl(int channelID, float volumeAdjustment) {
float oldValue;
{
QWriteLocker lock(&m_volumeLock);
oldValue = m_listenerVolumeAdjustments.value(channelID, 1.0f);
m_listenerVolumeAdjustments.insert(channelID, volumeAdjustment);
}
if (oldValue != volumeAdjustment) {
emit localVolumeAdjustmentsChanged(channelID, volumeAdjustment, oldValue);
}
}
float ChannelListener::getListenerLocalVolumeAdjustmentImpl(int channelID) const {
QReadLocker lock(&m_volumeLock);
return m_listenerVolumeAdjustments.value(channelID, 1.0f);
}
QHash< int, float > ChannelListener::getAllListenerLocalVolumeAdjustmentsImpl(bool filter) const {
QReadLocker lock(&m_volumeLock);
if (!filter) {
return m_listenerVolumeAdjustments;
} else {
QHash< int, float > volumeMap;
QHashIterator< int, float > it(m_listenerVolumeAdjustments);
while (it.hasNext()) {
it.next();
if (it.value() != 1.0f) {
volumeMap.insert(it.key(), it.value());
}
}
return volumeMap;
}
}
void ChannelListener::setInitialServerSyncDoneImpl(bool done) {
m_initialSyncDone.store(done);
}
#endif
void ChannelListener::clearImpl(){ { QWriteLocker lock(&m_listenerLock);
m_listeningUsers.clear();
m_listenedChannels.clear();
}
#ifdef MUMBLE
{
QWriteLocker lock(&m_volumeLock);
m_listenerVolumeAdjustments.clear();
}
#endif
}
ChannelListener &ChannelListener::get() {
return s_instance;
}
void ChannelListener::addListener(unsigned int userSession, int channelID) {
get().addListenerImpl(userSession, channelID);
}
void ChannelListener::addListener(const User *user, const Channel *channel) {
get().addListenerImpl(user->uiSession, channel->iId);
}
void ChannelListener::removeListener(unsigned int userSession, int channelID) {
get().removeListenerImpl(userSession, channelID);
}
void ChannelListener::removeListener(const User *user, const Channel *channel) {
get().removeListenerImpl(user->uiSession, channel->iId);
}
bool ChannelListener::isListening(unsigned int userSession, int channelID) {
return get().isListeningImpl(userSession, channelID);
}
bool ChannelListener::isListening(const User *user, const Channel *channel) {
return get().isListeningImpl(user->uiSession, channel->iId);
}
bool ChannelListener::isListeningToAny(unsigned int userSession) {
return get().isListeningToAnyImpl(userSession);
}
bool ChannelListener::isListeningToAny(const User *user) {
return get().isListeningToAnyImpl(user->uiSession);
}
bool ChannelListener::isListenedByAny(int channelID) {
return get().isListenedByAnyImpl(channelID);
}
bool ChannelListener::isListenedByAny(const Channel *channel) {
return get().isListenedByAnyImpl(channel->iId);
}
const QSet< unsigned int > ChannelListener::getListenersForChannel(int channelID) {
return get().getListenersForChannelImpl(channelID);
}
const QSet< unsigned int > ChannelListener::getListenersForChannel(const Channel *channel) {
return get().getListenersForChannelImpl(channel->iId);
}
const QSet< int > ChannelListener::getListenedChannelsForUser(unsigned int userSession) {
return get().getListenedChannelsForUserImpl(userSession);
}
const QSet< int > ChannelListener::getListenedChannelsForUser(const User *user) {
return get().getListenedChannelsForUserImpl(user->uiSession);
}
int ChannelListener::getListenerCountForChannel(int channelID) {
return get().getListenerCountForChannelImpl(channelID);
}
int ChannelListener::getListenerCountForChannel(const Channel *channel) {
return get().getListenerCountForChannelImpl(channel->iId);
}
int ChannelListener::getListenedChannelCountForUser(unsigned int userSession) {
return get().getListenedChannelCountForUserImpl(userSession);
}
int ChannelListener::getListenedChannelCountForUser(const User *user) {
return get().getListenedChannelCountForUserImpl(user->uiSession);
}
#ifdef MUMBLE
void ChannelListener::setListenerLocalVolumeAdjustment(int channelID, float volumeAdjustment) {
get().setListenerLocalVolumeAdjustmentImpl(channelID, volumeAdjustment);
}
void ChannelListener::setListenerLocalVolumeAdjustment(const Channel *channel, float volumeAdjustment) {
get().setListenerLocalVolumeAdjustmentImpl(channel->iId, volumeAdjustment);
}
float ChannelListener::getListenerLocalVolumeAdjustment(int channelID) {
return get().getListenerLocalVolumeAdjustmentImpl(channelID);
}
float ChannelListener::getListenerLocalVolumeAdjustment(const Channel *channel) {
return get().getListenerLocalVolumeAdjustmentImpl(channel->iId);
}
QHash< int, float > ChannelListener::getAllListenerLocalVolumeAdjustments(bool filter) {
return get().getAllListenerLocalVolumeAdjustmentsImpl(filter);
}
void ChannelListener::setInitialServerSyncDone(bool done) {
get().setInitialServerSyncDoneImpl(done);
}
void ChannelListener::saveToDB() {
if (!Global::get().sh || Global::get().sh->qbaDigest.isEmpty() || Global::get().uiSession == 0) {
// Can't save as we don't have enough context
return;
}
if (!get().m_initialSyncDone.load()) {
// If we were to save the listeners before the sync is done, we'd overwrite the list of listeners in the
// DB with an empty set, effectively erasing all set-up listeners.
qWarning("ChannelListener: Aborting save of user's listeners as initial ServerSync is not done yet");
return;
}
// Save the currently listened channels
Global::get().db->setChannelListeners(Global::get().sh->qbaDigest,
ChannelListener::getListenedChannelsForUser(Global::get().uiSession));
// And also the currently set volume adjustments (if they're not set to 1.0)
Global::get().db->setChannelListenerLocalVolumeAdjustments(
Global::get().sh->qbaDigest, ChannelListener::getAllListenerLocalVolumeAdjustments(true));
}
#endif
void ChannelListener::clear() {
get().clearImpl();
}

View File

@ -1,255 +0,0 @@
// Copyright 2020-2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_CHANNEL_LISTENER_H_
#define MUMBLE_CHANNEL_LISTENER_H_
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QReadWriteLock>
#include <QtCore/QSet>
#include <atomic>
class User;
class Channel;
/// This class serves as a namespace for storing information about ChannelListeners. This is a feature
/// that allows a user to listen to a channel without being in it. Kinda similar to linked channels
/// except that this is something each user can do individually.
class ChannelListener : public QObject {
private:
Q_OBJECT
Q_DISABLE_COPY(ChannelListener)
protected:
/// A lock for guarding m_listeningUsers as well as m_listenedChannels
mutable QReadWriteLock m_listenerLock;
/// A map between a user's session and a list of IDs of all channels the user is listening to
QHash< unsigned int, QSet< int > > m_listeningUsers;
/// A map between a channel's ID and a list of all user-sessions of users listening to that channel
QHash< int, QSet< unsigned int > > m_listenedChannels;
#ifdef MUMBLE
/// A lock for guarding m_listenerVolumeAdjustments
mutable QReadWriteLock m_volumeLock;
/// A map between channel IDs and local volume adjustments to be made for ChannelListeners
/// in that channel
QHash< int, float > m_listenerVolumeAdjustments;
/// A flag indicating whether the initial synchronization with the server has finished yet
std::atomic< bool > m_initialSyncDone;
#endif
/// The static ChannelListener instance returned by ChannelListener::get()
static ChannelListener s_instance;
/// Constructor
ChannelListener();
/// Adds a listener to the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
void addListenerImpl(unsigned int userSession, int channelID);
/// Removes a listener from the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
void removeListenerImpl(unsigned int userSession, int channelID);
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
/// @returns Whether the given user is listening to the given channel
bool isListeningImpl(unsigned int userSession, int channelID) const;
/// @param userSession The session ID of the user
/// @returns Whether this user is listening to any channel via the ChannelListener feature
bool isListeningToAnyImpl(unsigned int userSession) const;
/// @param channelID The ID of the channel
/// @returns Whether any user listens to this channel via the ChannelListener feature
bool isListenedByAnyImpl(int channelID) const;
/// @param channelID The ID of the channel
/// @returns A set of user sessions of users listening to the given channel
const QSet< unsigned int > getListenersForChannelImpl(int channelID) const;
/// @param userSession The session ID of the user
/// @returns A set of channel IDs of channels the given user is listening to
const QSet< int > getListenedChannelsForUserImpl(unsigned int userSession) const;
/// @param channelID The ID of the channel
/// @returns The amount of users that are listening to the given channel
int getListenerCountForChannelImpl(int channelID) const;
/// @param userSession The session ID of the user
/// @returns The amount of channels the given user is listening to
int getListenedChannelCountForUserImpl(unsigned int userSession) const;
#ifdef MUMBLE
/// Sets the local volume adjustment for any channelListener in the given channel.
///
/// @param channelID The ID of the channel
/// @param volumeAdjustment The volume adjustment to apply
void setListenerLocalVolumeAdjustmentImpl(int channelID, float volumeAdjustment);
/// @param channelID The ID of the channel
/// @param The local volume adjustment for the given channel. If none has been set,
/// 1.0f is being returned.
float getListenerLocalVolumeAdjustmentImpl(int channelID) const;
/// @param filter Whether to filter out adjustments of 1 (which have no effect)
/// @returns A map between channel IDs and the currently set volume adjustment
QHash< int, float > getAllListenerLocalVolumeAdjustmentsImpl(bool filter = false) const;
/// @done Whether the initial synchronization with the server is done yet
void setInitialServerSyncDoneImpl(bool done);
#endif
/// Clears all ChannelListeners and volume adjustments
void clearImpl();
public:
/// @returns The static ChannelListener instance
static ChannelListener &get();
/// Adds a listener to the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
static void addListener(unsigned int userSession, int channelID);
/// Adds a listener to the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
static void addListener(const User *user, const Channel *channel);
/// Removes a listener from the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
static void removeListener(unsigned int userSession, int channelID);
/// Removes a listener from the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
static void removeListener(const User *user, const Channel *channel);
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
/// @returns Whether the given user is listening to the given channel
static bool isListening(unsigned int userSession, int channelID);
/// @param channel A pointer to the channel object
/// @param user A pointer to the user object
/// @returns Whether the given user is listening to the given channel
static bool isListening(const User *user, const Channel *channel);
/// @param userSession The session ID of the user
/// @returns Whether this user is listening to any channel via the ChannelListener feature
static bool isListeningToAny(unsigned int userSession);
/// @param user A pointer to the user object
/// @returns Whether this user is listening to any channel via the ChannelListener feature
static bool isListeningToAny(const User *user);
/// @param channelID The ID of the channel
/// @returns Whether any user listens to this channel via the ChannelListener feature
static bool isListenedByAny(int channelID);
/// @param channel A pointer to the channel object
/// @returns Whether any user listens to this channel via the ChannelListener feature
static bool isListenedByAny(const Channel *channel);
/// @param channelID The ID of the channel
/// @returns A set of user sessions of users listening to the given channel
static const QSet< unsigned int > getListenersForChannel(int channelID);
/// @param channel A pointer to the channel object
/// @returns A set of user sessions of users listening to the given channel
static const QSet< unsigned int > getListenersForChannel(const Channel *channel);
/// @param userSession The session ID of the user
/// @returns A set of channel IDs of channels the given user is listening to
static const QSet< int > getListenedChannelsForUser(unsigned int userSession);
/// @param user A pointer to the user object
/// @returns A set of channel IDs of channels the given user is listening to
static const QSet< int > getListenedChannelsForUser(const User *user);
/// @param channelID The ID of the channel
/// @returns The amount of users that are listening to the given channel
static int getListenerCountForChannel(int channelID);
/// @param channel A pointer to the channel object
/// @returns The amount of users that are listening to the given channel
static int getListenerCountForChannel(const Channel *channel);
/// @param userSession The session ID of the user
/// @returns The amount of channels the given user is listening to
static int getListenedChannelCountForUser(unsigned int userSession);
/// @param user A pointer to the user object
/// @returns The amount of channels the given user is listening to
static int getListenedChannelCountForUser(const User *user);
#ifdef MUMBLE
/// Sets the local volume adjustment for any channelListener in the given channel.
///
/// @param channelID The ID of the channel
/// @param volumeAdjustment The volume adjustment to apply
static void setListenerLocalVolumeAdjustment(int channelID, float volumeAdjustment);
/// Sets the local volume adjustment for any channelListener in the given channel.
///
/// @param channel A pointer to the channel object
/// @param volumeAdjustment The volume adjustment to apply
static void setListenerLocalVolumeAdjustment(const Channel *channel, float volumeAdjustment);
/// @param channelID The ID of the channel
/// @param The local volume adjustment for the given channel. If none has been set,
/// 1.0f is being returned.
static float getListenerLocalVolumeAdjustment(int channelID);
/// @param channel A pointer to the channel object
/// @param The local volume adjustment for the given channel. If none has been set,
/// 1.0f is being returned.
static float getListenerLocalVolumeAdjustment(const Channel *channel);
/// @param filter Whether to filter out adjustments of 1 (which have no effect)
/// @returns A map between channel IDs and the currently set volume adjustment
static QHash< int, float > getAllListenerLocalVolumeAdjustments(bool filter = false);
/// @done Whether the initial synchronization with the server is done yet
static void setInitialServerSyncDone(bool done);
/// Saves the current ChannelListener state to the database.
/// NOTE: This function may only be called from the main thread!
static void saveToDB();
#endif
/// Clears all ChannelListeners and volume adjustments
static void clear();
signals:
#ifdef MUMBLE
void localVolumeAdjustmentsChanged(int channelID, float newAdjustment, float oldAdjustment);
#endif
};
#endif // MUMBLE_CHANNEL_LISTENER_H_

View File

@ -0,0 +1,165 @@
// Copyright 2020-2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "ChannelListenerManager.h"
#include "Channel.h"
#include "User.h"
#ifdef MUMBLE
# include "ServerHandler.h"
# include "Database.h"
# include "Global.h"
#endif
#include <QReadLocker>
#include <QWriteLocker>
ChannelListenerManager::ChannelListenerManager()
: QObject(nullptr), m_listenerLock(), m_listeningUsers(), m_listenedChannels()
#ifdef MUMBLE
,
m_volumeLock(), m_listenerVolumeAdjustments(), m_initialSyncDone(false)
#endif
{
}
void ChannelListenerManager::addListener(unsigned int userSession, int channelID) {
QWriteLocker lock(&m_listenerLock);
m_listeningUsers[userSession] << channelID;
m_listenedChannels[channelID] << userSession;
}
void ChannelListenerManager::removeListener(unsigned int userSession, int channelID) {
QWriteLocker lock(&m_listenerLock);
m_listeningUsers[userSession].remove(channelID);
m_listenedChannels[channelID].remove(userSession);
}
bool ChannelListenerManager::isListening(unsigned int userSession, int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID].contains(userSession);
}
bool ChannelListenerManager::isListeningToAny(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return !m_listeningUsers[userSession].isEmpty();
}
bool ChannelListenerManager::isListenedByAny(int channelID) const {
QReadLocker lock(&m_listenerLock);
return !m_listenedChannels[channelID].isEmpty();
}
const QSet< unsigned int > ChannelListenerManager::getListenersForChannel(int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID];
}
const QSet< int > ChannelListenerManager::getListenedChannelsForUser(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return m_listeningUsers[userSession];
}
int ChannelListenerManager::getListenerCountForChannel(int channelID) const {
QReadLocker lock(&m_listenerLock);
return m_listenedChannels[channelID].size();
}
int ChannelListenerManager::getListenedChannelCountForUser(unsigned int userSession) const {
QReadLocker lock(&m_listenerLock);
return m_listeningUsers[userSession].size();
}
#ifdef MUMBLE
void ChannelListenerManager::setListenerLocalVolumeAdjustment(int channelID, float volumeAdjustment) {
float oldValue;
{
QWriteLocker lock(&m_volumeLock);
oldValue = m_listenerVolumeAdjustments.value(channelID, 1.0f);
m_listenerVolumeAdjustments.insert(channelID, volumeAdjustment);
}
if (oldValue != volumeAdjustment) {
emit localVolumeAdjustmentsChanged(channelID, volumeAdjustment, oldValue);
}
}
float ChannelListenerManager::getListenerLocalVolumeAdjustment(int channelID) const {
QReadLocker lock(&m_volumeLock);
return m_listenerVolumeAdjustments.value(channelID, 1.0f);
}
QHash< int, float > ChannelListenerManager::getAllListenerLocalVolumeAdjustments(bool filter) const {
QReadLocker lock(&m_volumeLock);
if (!filter) {
return m_listenerVolumeAdjustments;
} else {
QHash< int, float > volumeMap;
QHashIterator< int, float > it(m_listenerVolumeAdjustments);
while (it.hasNext()) {
it.next();
if (it.value() != 1.0f) {
volumeMap.insert(it.key(), it.value());
}
}
return volumeMap;
}
}
void ChannelListenerManager::setInitialServerSyncDone(bool done) {
m_initialSyncDone.store(done);
}
void ChannelListenerManager::saveToDB() const {
if (!Global::get().sh || Global::get().sh->qbaDigest.isEmpty() || Global::get().uiSession == 0) {
// Can't save as we don't have enough context
return;
}
if (!m_initialSyncDone.load()) {
// If we were to save the listeners before the sync is done, we'd overwrite the list of listeners in the
// DB with an empty set, effectively erasing all set-up listeners.
qWarning("ChannelListener: Aborting save of user's listeners as initial ServerSync is not done yet");
return;
}
// Save the currently listened channels
Global::get().db->setChannelListeners(Global::get().sh->qbaDigest,
getListenedChannelsForUser(Global::get().uiSession));
// And also the currently set volume adjustments (if they're not set to 1.0)
Global::get().db->setChannelListenerLocalVolumeAdjustments(Global::get().sh->qbaDigest,
getAllListenerLocalVolumeAdjustments(true));
}
#endif
void ChannelListenerManager::clear() {
{
QWriteLocker lock(&m_listenerLock);
m_listeningUsers.clear();
m_listenedChannels.clear();
}
#ifdef MUMBLE
{
QWriteLocker lock(&m_volumeLock);
m_listenerVolumeAdjustments.clear();
}
#endif
}

View File

@ -0,0 +1,122 @@
// Copyright 2020-2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_CHANNELLISTENERMANAGER_H_
#define MUMBLE_CHANNELLISTENERMANAGER_H_
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QReadWriteLock>
#include <QtCore/QSet>
#include <atomic>
class User;
class Channel;
/// This class serves as a namespace for storing information about ChannelListeners. This is a feature
/// that allows a user to listen to a channel without being in it. Kinda similar to linked channels
/// except that this is something each user can do individually.
class ChannelListenerManager : public QObject {
private:
Q_OBJECT
Q_DISABLE_COPY(ChannelListenerManager)
protected:
/// A lock for guarding m_listeningUsers as well as m_listenedChannels
mutable QReadWriteLock m_listenerLock;
/// A map between a user's session and a list of IDs of all channels the user is listening to
QHash< unsigned int, QSet< int > > m_listeningUsers;
/// A map between a channel's ID and a list of all user-sessions of users listening to that channel
QHash< int, QSet< unsigned int > > m_listenedChannels;
#ifdef MUMBLE
/// A lock for guarding m_listenerVolumeAdjustments
mutable QReadWriteLock m_volumeLock;
/// A map between channel IDs and local volume adjustments to be made for ChannelListeners
/// in that channel
QHash< int, float > m_listenerVolumeAdjustments;
/// A flag indicating whether the initial synchronization with the server has finished yet
std::atomic< bool > m_initialSyncDone;
#endif
public:
/// Constructor
explicit ChannelListenerManager();
/// Adds a listener to the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
void addListener(unsigned int userSession, int channelID);
/// Removes a listener from the channel.
///
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
void removeListener(unsigned int userSession, int channelID);
/// @param userSession The session ID of the user
/// @param channelID The ID of the channel
/// @returns Whether the given user is listening to the given channel
bool isListening(unsigned int userSession, int channelID) const;
/// @param userSession The session ID of the user
/// @returns Whether this user is listening to any channel via the ChannelListener feature
bool isListeningToAny(unsigned int userSession) const;
/// @param channelID The ID of the channel
/// @returns Whether any user listens to this channel via the ChannelListener feature
bool isListenedByAny(int channelID) const;
/// @param channelID The ID of the channel
/// @returns A set of user sessions of users listening to the given channel
const QSet< unsigned int > getListenersForChannel(int channelID) const;
/// @param userSession The session ID of the user
/// @returns A set of channel IDs of channels the given user is listening to
const QSet< int > getListenedChannelsForUser(unsigned int userSession) const;
/// @param channelID The ID of the channel
/// @returns The amount of users that are listening to the given channel
int getListenerCountForChannel(int channelID) const;
/// @param userSession The session ID of the user
/// @returns The amount of channels the given user is listening to
int getListenedChannelCountForUser(unsigned int userSession) const;
#ifdef MUMBLE
/// Sets the local volume adjustment for any channelListener in the given channel.
///
/// @param channelID The ID of the channel
/// @param volumeAdjustment The volume adjustment to apply
void setListenerLocalVolumeAdjustment(int channelID, float volumeAdjustment);
/// @param channelID The ID of the channel
/// @param The local volume adjustment for the given channel. If none has been set,
/// 1.0f is being returned.
float getListenerLocalVolumeAdjustment(int channelID) const;
/// @param filter Whether to filter out adjustments of 1 (which have no effect)
/// @returns A map between channel IDs and the currently set volume adjustment
QHash< int, float > getAllListenerLocalVolumeAdjustments(bool filter = false) const;
/// @done Whether the initial synchronization with the server is done yet
void setInitialServerSyncDone(bool done);
/// Saves the current ChannelListener state to the database.
/// NOTE: This function may only be called from the main thread!
void saveToDB() const;
#endif
/// Clears all ChannelListeners and volume adjustments
void clear();
signals:
#ifdef MUMBLE
void localVolumeAdjustmentsChanged(int channelID, float newAdjustment, float oldAdjustment);
#endif
};
#endif // MUMBLE_CHANNELLISTENERMANAGER_H_

View File

@ -9,7 +9,7 @@
#include "AudioOutputSample.h"
#include "AudioOutputSpeech.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "Message.h"
#include "PacketDataStream.h"
#include "PluginManager.h"
@ -504,12 +504,12 @@ bool AudioOutput::mix(void *outbuff, unsigned int frameCount) {
user = speech->p;
volumeAdjustment *= user->getLocalVolumeAdjustments();
if (user->cChannel && ChannelListener::isListening(Global::get().uiSession, user->cChannel->iId)
if (user->cChannel && Global::get().channelListenerManager->isListening(Global::get().uiSession, user->cChannel->iId)
&& (speech->ucFlags & SpeechFlags::Listen)) {
// We are receiving this audio packet only because we are listening to the channel
// the speaking user is in. Thus we receive the audio via our "listener proxy".
// Thus we'll apply the volume adjustment for our listener proxy as well
volumeAdjustment *= ChannelListener::getListenerLocalVolumeAdjustment(user->cChannel);
volumeAdjustment *= Global::get().channelListenerManager->getListenerLocalVolumeAdjustment(user->cChannel->iId);
}
if (prioritySpeakerActive) {

View File

@ -285,8 +285,8 @@ set(MUMBLE_SOURCES
"${SHARED_SOURCE_DIR}/ACL.h"
"${SHARED_SOURCE_DIR}/Channel.cpp"
"${SHARED_SOURCE_DIR}/Channel.h"
"${SHARED_SOURCE_DIR}/ChannelListener.cpp"
"${SHARED_SOURCE_DIR}/ChannelListener.h"
"${SHARED_SOURCE_DIR}/ChannelListenerManager.cpp"
"${SHARED_SOURCE_DIR}/ChannelListenerManager.h"
"${SHARED_SOURCE_DIR}/Connection.cpp"
"${SHARED_SOURCE_DIR}/Connection.h"
"${SHARED_SOURCE_DIR}/Group.cpp"

View File

@ -124,6 +124,8 @@ Global::Global(const QString &qsConfigPath) {
bDebugDumpInput = false;
bDebugPrintQueue = false;
channelListenerManager = std::make_unique<ChannelListenerManager>();
#if defined(Q_OS_WIN)
QString appdata;
wchar_t appData[MAX_PATH];

View File

@ -13,6 +13,9 @@
#include "Settings.h"
#include "Timer.h"
#include "Version.h"
#include "ChannelListenerManager.h"
#include <memory>
// Global helper class to spread variables around across threads.
@ -107,6 +110,7 @@ public:
QString windowTitlePostfix;
bool bDebugDumpInput;
bool bDebugPrintQueue;
std::unique_ptr<ChannelListenerManager> channelListenerManager;
bool bHappyEaster;
static const char ccHappyEaster[];

View File

@ -5,8 +5,9 @@
#include "ListenerLocalVolumeDialog.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "ClientUser.h"
#include "Global.h"
#include <QtWidgets/QPushButton>
@ -16,7 +17,7 @@ ListenerLocalVolumeDialog::ListenerLocalVolumeDialog(ClientUser *user, Channel *
: QDialog(parent), m_user(user), m_channel(channel) {
setupUi(this);
m_initialAdjustemt = ChannelListener::getListenerLocalVolumeAdjustment(m_channel);
m_initialAdjustemt = Global::get().channelListenerManager->getListenerLocalVolumeAdjustment(m_channel->iId);
// Decibel formula: +6db = *2
// Calculate the db-shift from the set volume-faactor
@ -35,7 +36,7 @@ void ListenerLocalVolumeDialog::on_qsbUserLocalVolume_valueChanged(int value) {
// Decibel formula: +6db = *2
// Calculate the volume-factor for the set db-shift
ChannelListener::setListenerLocalVolumeAdjustment(m_channel,
Global::get().channelListenerManager->setListenerLocalVolumeAdjustment(m_channel->iId,
static_cast< float >(pow(2.0, qsUserLocalVolume->value() / 6.0)));
}
@ -53,7 +54,7 @@ void ListenerLocalVolumeDialog::on_qbbUserLocalVolume_clicked(QAbstractButton *b
void ListenerLocalVolumeDialog::reject() {
// Restore to what has been set before the dialog
ChannelListener::setListenerLocalVolumeAdjustment(m_channel, m_initialAdjustemt);
Global::get().channelListenerManager->setListenerLocalVolumeAdjustment(m_channel->iId, m_initialAdjustemt);
QDialog::reject();
}

View File

@ -30,7 +30,7 @@
# include "OverlayClient.h"
#endif
#include "../SignalCurry.h"
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "ListenerLocalVolumeDialog.h"
#include "Markdown.h"
#include "PTTButtonWidget.h"
@ -331,7 +331,7 @@ void MainWindow::setupGui() {
QObject::connect(
this, &MainWindow::userRemovedChannelListener, pmModel,
static_cast< void (UserModel::*)(const ClientUser *, const Channel *) >(&UserModel::removeChannelListener));
QObject::connect(&ChannelListener::get(), &ChannelListener::localVolumeAdjustmentsChanged, pmModel,
QObject::connect(Global::get().channelListenerManager.get(), &ChannelListenerManager::localVolumeAdjustmentsChanged, pmModel,
&UserModel::on_channelListenerLocalVolumeAdjustmentChanged);
// connect slots to PluginManager
@ -951,7 +951,7 @@ void MainWindow::toggleSearchDialogVisibility() {
static void recreateServerHandler() {
// New server connection, so the sync has not happened yet
ChannelListener::setInitialServerSyncDone(false);
Global::get().channelListenerManager->setInitialServerSyncDone(false);
ServerHandlerPtr sh = Global::get().sh;
if (sh && sh->isRunning()) {
@ -1696,7 +1696,7 @@ void MainWindow::qmListener_aboutToShow() {
qmListener->addAction(qaListenerLocalVolume);
if (cContextChannel) {
qmListener->addAction(qaChannelListen);
qaChannelListen->setChecked(ChannelListener::isListening(Global::get().uiSession, cContextChannel->iId));
qaChannelListen->setChecked(Global::get().channelListenerManager->isListening(Global::get().uiSession, cContextChannel->iId));
}
} else {
qmListener->addAction(qaEmpty);
@ -2148,7 +2148,7 @@ void MainWindow::qmChannel_aboutToShow() {
// If the server's version is less than 1.4, the listening feature is not supported yet
// and thus it doesn't make sense to show the action for it
qmChannel->addAction(qaChannelListen);
qaChannelListen->setChecked(ChannelListener::isListening(Global::get().uiSession, c->iId));
qaChannelListen->setChecked(Global::get().channelListenerManager->isListening(Global::get().uiSession, c->iId));
}
qmChannel->addSeparator();
@ -3198,11 +3198,11 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re
if (Global::get().sh->hasSynchronized()) {
// Note that the saving of the ChannelListeners has to be done, before resetting Global::get().uiSession
// Save ChannelListeners
ChannelListener::saveToDB();
Global::get().channelListenerManager->saveToDB();
}
// clear ChannelListener
ChannelListener::clear();
Global::get().channelListenerManager->clear();
Global::get().uiSession = 0;
Global::get().pPermissions = ChanACL::None;

View File

@ -23,7 +23,7 @@
#ifdef USE_OVERLAY
# include "Overlay.h"
#endif
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "PluginManager.h"
#include "ServerHandler.h"
#include "TalkingUI.h"
@ -188,11 +188,11 @@ void MainWindow::msgServerSync(const MumbleProto::ServerSync &msg) {
QList< int > localListeners = Global::get().db->getChannelListeners(Global::get().sh->qbaDigest);
if (!localListeners.isEmpty()) {
ChannelListener::setInitialServerSyncDone(false);
Global::get().channelListenerManager->setInitialServerSyncDone(false);
Global::get().sh->startListeningToChannels(localListeners);
} else {
// If there are no listeners, then no synchronization is needed in the first place
ChannelListener::setInitialServerSyncDone(true);
Global::get().channelListenerManager->setInitialServerSyncDone(true);
}
{
@ -201,14 +201,14 @@ void MainWindow::msgServerSync(const MumbleProto::ServerSync &msg) {
// officially exist. Therefore some code that would receive the change-event would try to get the respective
// listener and fail due to it not existing yet. Therefore we block all signals while setting the volume
// adjustments.
const QSignalBlocker blocker(ChannelListener::get());
const QSignalBlocker blocker(Global::get().channelListenerManager.get());
QHash< int, float > volumeMap =
Global::get().db->getChannelListenerLocalVolumeAdjustments(Global::get().sh->qbaDigest);
QHashIterator< int, float > it(volumeMap);
while (it.hasNext()) {
it.next();
ChannelListener::setListenerLocalVolumeAdjustment(it.key(), it.value());
Global::get().channelListenerManager->setListenerLocalVolumeAdjustment(it.key(), it.value());
}
}
@ -487,7 +487,7 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) {
continue;
}
ChannelListener::addListener(pDst, c);
Global::get().channelListenerManager->addListener(pDst->uiSession, c->iId);
emit userAddedChannelListener(pDst, c);
QString logMsg;
@ -499,7 +499,7 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) {
// succecssfully told the server that we are listening to the respective channels. Even if this message
// here has nothing to do with the actual initial synchronization, this means that we have been connected
// to the server long enough for the synchronization to be done.
ChannelListener::setInitialServerSyncDone(true);
Global::get().channelListenerManager->setInitialServerSyncDone(true);
} else if (pSelf && pSelf->cChannel == c) {
logMsg = tr("%1 started listening to your channel").arg(Log::formatClientUser(pDst, Log::Target));
}
@ -516,7 +516,7 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) {
continue;
}
ChannelListener::removeListener(pDst, c);
Global::get().channelListenerManager->removeListener(pDst->uiSession, c->iId);
emit userRemovedChannelListener(pDst, c);
QString logMsg;

View File

@ -5,7 +5,7 @@
#include "TalkingUI.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "ClientUser.h"
#include "MainWindow.h"
#include "TalkingUIComponent.h"
@ -772,7 +772,7 @@ void TalkingUI::on_settingsChanged() {
removeAllListeners();
if (Global::get().s.bTalkingUI_ShowLocalListeners) {
if (self) {
const QSet< int > channels = ChannelListener::getListenedChannelsForUser(self->uiSession);
const QSet< int > channels = Global::get().channelListenerManager->getListenedChannelsForUser(self->uiSession);
for (int currentChannelID : channels) {
const Channel *channel = Channel::get(currentChannelID);

View File

@ -15,7 +15,7 @@
#ifdef USE_OVERLAY
# include "Overlay.h"
#endif
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "ServerHandler.h"
#include "Usage.h"
#include "User.h"
@ -1972,7 +1972,7 @@ QString UserModel::createDisplayString(const ClientUser &user, bool isChannelLis
if (isChannelListener) {
if (parentChannel && user.uiSession == Global::get().uiSession) {
// Only the listener of the local user can have a volume adjustment
volumeAdjustment = ChannelListener::getListenerLocalVolumeAdjustment(parentChannel->iId);
volumeAdjustment = Global::get().channelListenerManager->getListenerLocalVolumeAdjustment(parentChannel->iId);
}
} else {
volumeAdjustment = user.getLocalVolumeAdjustments();

View File

@ -28,7 +28,7 @@
#endif
#include "ApplicationPalette.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "ChannelListenerManager.h"
#include "ClientUser.h"
#include "CrashReporter.h"
#include "EnvUtils.h"
@ -671,7 +671,7 @@ int main(int argc, char **argv) {
&TalkingUI::on_channelListenerAdded);
QObject::connect(Global::get().mw, &MainWindow::userRemovedChannelListener, Global::get().talkingUI,
&TalkingUI::on_channelListenerRemoved);
QObject::connect(&ChannelListener::get(), &ChannelListener::localVolumeAdjustmentsChanged, Global::get().talkingUI,
QObject::connect(Global::get().channelListenerManager.get(), &ChannelListenerManager::localVolumeAdjustmentsChanged, Global::get().talkingUI,
&TalkingUI::on_channelListenerLocalVolumeAdjustmentChanged);
QObject::connect(Global::get().mw, &MainWindow::serverSynchronized, Global::get().talkingUI,

View File

@ -41,8 +41,8 @@ set(MURMUR_SOURCES
"${SHARED_SOURCE_DIR}/ACL.h"
"${SHARED_SOURCE_DIR}/Channel.cpp"
"${SHARED_SOURCE_DIR}/Channel.h"
"${SHARED_SOURCE_DIR}/ChannelListener.cpp"
"${SHARED_SOURCE_DIR}/ChannelListener.h"
"${SHARED_SOURCE_DIR}/ChannelListenerManager.cpp"
"${SHARED_SOURCE_DIR}/ChannelListenerManager.h"
"${SHARED_SOURCE_DIR}/Connection.cpp"
"${SHARED_SOURCE_DIR}/Connection.h"
"${SHARED_SOURCE_DIR}/Group.cpp"

View File

@ -5,7 +5,6 @@
#include "ACL.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "Connection.h"
#include "Group.h"
#include "Message.h"
@ -469,7 +468,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
if (!u->qsHash.isEmpty())
mpus.set_hash(u8(u->qsHash));
foreach (int channelID, ChannelListener::getListenedChannelsForUser(u)) {
foreach (int channelID, m_channelListenerManager.getListenedChannelsForUser(u->uiSession)) {
mpus.add_listening_channel_add(channelID);
}
@ -700,7 +699,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
}
if (Meta::mp.iMaxListenersPerChannel >= 0
&& Meta::mp.iMaxListenersPerChannel - ChannelListener::getListenerCountForChannel(c) - 1 < 0) {
&& Meta::mp.iMaxListenersPerChannel - m_channelListenerManager.getListenerCountForChannel(c->iId) - 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"));
@ -708,7 +707,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
}
if (Meta::mp.iMaxListenerProxiesPerUser >= 0
&& Meta::mp.iMaxListenerProxiesPerUser - ChannelListener::getListenedChannelCountForUser(uSource)
&& Meta::mp.iMaxListenerProxiesPerUser - m_channelListenerManager.getListenedChannelCountForUser(uSource->uiSession)
- passedChannelListener - 1
< 0) {
// A limit for the amount of listener proxies per user is set and it has been reached already
@ -927,7 +926,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
// Handle channel listening
// Note that it is important to handle the listening channels after channel-joins
foreach (Channel *c, listeningChannelsAdd) {
ChannelListener::addListener(uSource, c);
m_channelListenerManager.addListener(uSource->uiSession, c->iId);
log(QString::fromLatin1("\"%1\" is now listening to channel \"%2\"").arg(QString(*uSource)).arg(QString(*c)));
}
@ -935,7 +934,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
Channel *c = qhChannels.value(msg.listening_channel_remove(i));
if (c) {
ChannelListener::removeListener(uSource, c);
m_channelListenerManager.removeListener(uSource->uiSession, c->iId);
log(QString::fromLatin1("\"%1\" is no longer listening to \"%2\"").arg(QString(*uSource)).arg(QString(*c)));
}
@ -1420,7 +1419,7 @@ void Server::msgTextMessage(ServerUser *uSource, MumbleProto::TextMessage &msg)
foreach (User *p, c->qlUsers) { users.insert(static_cast< ServerUser * >(p)); }
// Users only listening in that channel
foreach (unsigned int session, ChannelListener::getListenersForChannel(c)) {
foreach (unsigned int session, m_channelListenerManager.getListenersForChannel(c->iId)) {
ServerUser *currentUser = qhUsers.value(session);
if (currentUser) {
users.insert(currentUser);
@ -1460,7 +1459,7 @@ void Server::msgTextMessage(ServerUser *uSource, MumbleProto::TextMessage &msg)
// Users directly in that channel
foreach (User *p, c->qlUsers) { users.insert(static_cast< ServerUser * >(p)); }
// Users only listening in that channel
foreach (unsigned int session, ChannelListener::getListenersForChannel(c)) {
foreach (unsigned int session, m_channelListenerManager.getListenersForChannel(c->iId)) {
ServerUser *currentUser = qhUsers.value(session);
if (currentUser) {
users.insert(currentUser);

View File

@ -7,7 +7,6 @@
#include "Ban.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "Group.h"
#include "Meta.h"
#include "MurmurI.h"
@ -1736,7 +1735,7 @@ static void impl_Server_isListening(const ::Murmur::AMD_Server_isListeningPtr cb
NEED_CHANNEL;
NEED_PLAYER;
cb->ice_response(ChannelListener::isListening(user, channel));
cb->ice_response(server->m_channelListenerManager.isListening(user->uiSession, channel->iId));
}
static void impl_Server_getListeningChannels(const ::Murmur::AMD_Server_getListeningChannelsPtr cb, int server_id,
@ -1745,7 +1744,7 @@ static void impl_Server_getListeningChannels(const ::Murmur::AMD_Server_getListe
NEED_PLAYER;
::Murmur::IntList channelIDs;
foreach (int currentChannelID, ChannelListener::getListenedChannelsForUser(user)) {
foreach (int currentChannelID, server->m_channelListenerManager.getListenedChannelsForUser(user->uiSession)) {
channelIDs.push_back(currentChannelID);
}
@ -1758,7 +1757,7 @@ static void impl_Server_getListeningUsers(const ::Murmur::AMD_Server_getListenin
NEED_CHANNEL;
::Murmur::IntList userSessions;
foreach (unsigned int currentSession, ChannelListener::getListenersForChannel(channel)) {
foreach (unsigned int currentSession, server->m_channelListenerManager.getListenersForChannel(channel->iId)) {
userSessions.push_back(currentSession);
}

View File

@ -10,7 +10,6 @@
#endif
#include "Channel.h"
#include "ChannelListener.h"
#include "Group.h"
#include "Meta.h"
#include "Server.h"
@ -539,12 +538,12 @@ void Server::disconnectListener(QObject *obj) {
}
void Server::startListeningToChannel(ServerUser *user, Channel *cChannel) {
if (ChannelListener::isListening(user, cChannel)) {
if (m_channelListenerManager.isListening(user->uiSession, cChannel->iId)) {
// The user is already listening to this channel
return;
}
ChannelListener::addListener(user, cChannel);
m_channelListenerManager.addListener(user->uiSession, cChannel->iId);
MumbleProto::UserState mpus;
mpus.set_session(user->uiSession);
@ -555,12 +554,12 @@ void Server::startListeningToChannel(ServerUser *user, Channel *cChannel) {
}
void Server::stopListeningToChannel(ServerUser *user, Channel *cChannel) {
if (!ChannelListener::isListening(user, cChannel)) {
if (!m_channelListenerManager.isListening(user->uiSession, cChannel->iId)) {
// The user is not listening to this channel
return;
}
ChannelListener::removeListener(user, cChannel);
m_channelListenerManager.removeListener(user->uiSession, cChannel->iId);
MumbleProto::UserState mpus;
mpus.set_session(user->uiSession);

View File

@ -7,7 +7,6 @@
#include "ACL.h"
#include "Channel.h"
#include "ChannelListener.h"
#include "Connection.h"
#include "EnvUtils.h"
#include "Group.h"
@ -1170,7 +1169,7 @@ void Server::processMsg(ServerUser *u, const char *data, int len) {
buffer[0] = static_cast< char >(type | SpeechFlags::Normal);
// Send audio to all users that are listening to the channel
foreach (unsigned int currentSession, ChannelListener::getListenersForChannel(c)) {
foreach (unsigned int currentSession, m_channelListenerManager.getListenersForChannel(c->iId)) {
ServerUser *pDst = static_cast< ServerUser * >(qhUsers.value(currentSession));
if (pDst) {
listeningUsers << pDst;
@ -1200,16 +1199,16 @@ void Server::processMsg(ServerUser *u, const char *data, int len) {
// Send the audio stream to all users that are listening to the linked channel but are not
// in the original channel the audio is coming from nor are they listening to the orignal
// channel (in these cases they have received the audio already).
foreach (unsigned int currentSession, ChannelListener::getListenersForChannel(l)) {
foreach (unsigned int currentSession, m_channelListenerManager.getListenersForChannel(l->iId)) {
ServerUser *pDst = static_cast< ServerUser * >(qhUsers.value(currentSession));
if (pDst && pDst->cChannel != c && !ChannelListener::isListening(pDst, c)) {
if (pDst && pDst->cChannel != c && !m_channelListenerManager.isListening(pDst->uiSession, c->iId)) {
listeningUsers << pDst;
}
}
// Send audio to users in the linked channel
foreach (User *p, l->qlUsers) {
if (!ChannelListener::isListening(p->uiSession, c->iId)) {
if (!m_channelListenerManager.isListening(p->uiSession, c->iId)) {
ServerUser *pDst = static_cast< ServerUser * >(p);
// As we send the audio to this particular user here, we want to make sure to not send it
@ -1248,7 +1247,7 @@ void Server::processMsg(ServerUser *u, const char *data, int len) {
if (ChanACL::hasPermission(u, wc, ChanACL::Whisper, &acCache)) {
foreach (User *p, wc->qlUsers) { channel.insert(static_cast< ServerUser * >(p)); }
foreach (unsigned int currentSession, ChannelListener::getListenersForChannel(wc)) {
foreach (unsigned int currentSession, m_channelListenerManager.getListenersForChannel(wc->iId)) {
ServerUser *pDst = static_cast< ServerUser * >(qhUsers.value(currentSession));
if (pDst) {
@ -1276,7 +1275,7 @@ void Server::processMsg(ServerUser *u, const char *data, int len) {
}
}
foreach (unsigned int currentSession, ChannelListener::getListenersForChannel(tc)) {
foreach (unsigned int currentSession, m_channelListenerManager.getListenersForChannel(tc->iId)) {
ServerUser *pDst = static_cast< ServerUser * >(qhUsers.value(currentSession));
if (pDst && (!group || Group::isMember(tc, tc, qsg, pDst))) {
@ -1637,17 +1636,17 @@ void Server::connectionClosed(QAbstractSocket::SocketError err, const QString &r
setLastDisconnect(u);
if (u->sState == ServerUser::Authenticated) {
if (ChannelListener::isListeningToAny(u)) {
if (m_channelListenerManager.isListeningToAny(u->uiSession)) {
// Send nessage to all other clients that this particular user won't be listening
// to any channel anymore
MumbleProto::UserState mpus;
mpus.set_session(u->uiSession);
foreach (int channelID, ChannelListener::getListenedChannelsForUser(u)) {
foreach (int channelID, m_channelListenerManager.getListenedChannelsForUser(u->uiSession)) {
mpus.add_listening_channel_remove(channelID);
// Also remove the client from the list on the server
ChannelListener::removeListener(u->uiSession, channelID);
m_channelListenerManager.removeListener(u->uiSession, channelID);
}
sendExcept(u, mpus);
@ -1868,8 +1867,8 @@ void Server::removeChannel(Channel *chan, Channel *dest) {
emit userStateChanged(p);
}
foreach (unsigned int userSession, ChannelListener::getListenersForChannel(chan)) {
ChannelListener::removeListener(userSession, chan->iId);
foreach (unsigned int userSession, m_channelListenerManager.getListenersForChannel(chan->iId)) {
m_channelListenerManager.removeListener(userSession, chan->iId);
// Notify that all clients that have been listening to this channel, will do so no more
MumbleProto::UserState mpus;

View File

@ -14,6 +14,7 @@
#include "ACL.h"
#include "Ban.h"
#include "ChannelListenerManager.h"
#include "HostAddress.h"
#include "Message.h"
#include "Mumble.pb.h"
@ -168,6 +169,8 @@ public:
bool bValid;
ChannelListenerManager m_channelListenerManager;
void readParams();
int iCodecAlpha;