mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
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:
commit
05db5fe6fc
@ -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();
|
||||
}
|
||||
@ -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_
|
||||
165
src/ChannelListenerManager.cpp
Normal file
165
src/ChannelListenerManager.cpp
Normal 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
|
||||
}
|
||||
122
src/ChannelListenerManager.h
Normal file
122
src/ChannelListenerManager.h
Normal 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_
|
||||
@ -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) {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user