Skip to content
Permalink
Browse files

Add local per-user volume adjustment.

Fixes #1156
  • Loading branch information...
Fredrik Nordin authored and mkrautz committed Oct 15, 2015
1 parent 0ac822a commit 15f47f4f858ea0a95145e12f43f1c3f8e0d326ef
@@ -491,15 +491,16 @@ bool AudioOutput::mix(void *outbuff, unsigned int nsamp) {
const float * RESTRICT pfBuffer = aop->pfBuffer;
float volumeAdjustment = 1;

if (prioritySpeakerActive) {
AudioOutputSpeech *speech = qobject_cast<AudioOutputSpeech *>(aop);
if (speech) {
const ClientUser* user = speech->p;
AudioOutputSpeech *speech = qobject_cast<AudioOutputSpeech *>(aop);
if (speech) {
const ClientUser *user = speech->p;
volumeAdjustment *= user->fLocalVolume;
if (prioritySpeakerActive) {

if (user->tsState != Settings::Whispering
&& !user->bPrioritySpeaker) {

volumeAdjustment = adjustFactor;
volumeAdjustment *= adjustFactor;
}
}
}
@@ -49,6 +49,7 @@ ClientUser::ClientUser(QObject *p) : QObject(p),
bLocalMute(false),
fPowerMin(0.0f),
fPowerMax(0.0f),
fLocalVolume(1.0f),
fAverageAvailable(0.0f),
iFrames(0),
iSequence(0) {
@@ -55,6 +55,7 @@ class ClientUser : public QObject, public User {

float fPowerMin, fPowerMax;
float fAverageAvailable;
float fLocalVolume;

#ifdef REPORT_JITTER
QMutex qmTiming;
@@ -165,6 +165,8 @@ Database::Database() {

execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `muted` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT)"));
execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `muted_hash` ON `muted`(`hash`)"));
execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `volume` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT, `volume` FLOAT)"));
execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `volume_hash` ON `volume`(`hash`)"));

//Note: A previous snapshot version created a table called 'hidden'
execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `filtered_channels` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `server_cert_digest` TEXT NOT NULL, `channel_id` INTEGER NOT NULL)"));
@@ -273,6 +275,27 @@ bool Database::isLocalMuted(const QString &hash) {
return false;
}

void Database::setUserLocalVolume(const QString &hash, float volume) {
QSqlQuery query;

query.prepare(QLatin1String("INSERT OR REPLACE INTO `volume` (`hash`, `volume`) VALUES (?,?)"));
query.addBindValue(hash);
query.addBindValue(QString::number(volume));
execQueryAndLogFailure(query);
}

float Database::getUserLocalVolume(const QString &hash) {
QSqlQuery query;

query.prepare(QLatin1String("SELECT `volume` FROM `volume` WHERE `hash` = ?"));
query.addBindValue(hash);
execQueryAndLogFailure(query);
if (query.first()) {
return query.value(0).toString().toFloat();
}
return 1.0f;
}

void Database::setLocalMuted(const QString &hash, bool muted) {
QSqlQuery query;

@@ -60,6 +60,9 @@ class Database : public QObject {
static bool isLocalMuted(const QString &hash);
static void setLocalMuted(const QString &hash, bool muted);

static float getUserLocalVolume(const QString &hash);
static void setUserLocalVolume(const QString &hash, float volume);

static bool isChannelFiltered(const QByteArray &server_cert_digest, const int channel_id);
static void setChannelFiltered(const QByteArray &server_cert_digest, const int channel_id, bool hidden);

@@ -62,6 +62,7 @@
#include "UserEdit.h"
#include "UserInformation.h"
#include "UserModel.h"
#include "UserLocalVolumeDialog.h"
#include "VersionCheck.h"
#include "ViewCert.h"
#include "VoiceRecorderDialog.h"
@@ -1313,6 +1314,7 @@ void MainWindow::qmUser_aboutToShow() {
qmUser->addAction(qaUserPrioritySpeaker);
qmUser->addAction(qaUserLocalMute);
qmUser->addAction(qaUserLocalIgnore);
qmUser->addAction(qaUserLocalVolume);

if (self)
qmUser->addAction(qaSelfComment);
@@ -1369,6 +1371,7 @@ void MainWindow::qmUser_aboutToShow() {
qaUserBan->setEnabled(false);
qaUserTextMessage->setEnabled(false);
qaUserLocalMute->setEnabled(false);
qaUserLocalVolume->setEnabled(false);
qaUserLocalIgnore->setEnabled(false);
qaUserCommentReset->setEnabled(false);
qaUserTextureReset->setEnabled(false);
@@ -1378,6 +1381,7 @@ void MainWindow::qmUser_aboutToShow() {
qaUserBan->setEnabled(! self);
qaUserTextMessage->setEnabled(true);
qaUserLocalMute->setEnabled(! self);
qaUserLocalVolume->setEnabled(! self);
qaUserLocalIgnore->setEnabled(! self);
qaUserCommentReset->setEnabled(! p->qbaCommentHash.isEmpty() && (g.pPermissions & (ChanACL::Move | ChanACL::Write)));
qaUserTextureReset->setEnabled(! p->qbaTextureHash.isEmpty() && (g.pPermissions & (ChanACL::Move | ChanACL::Write)));
@@ -1434,6 +1438,26 @@ void MainWindow::on_qaUserLocalIgnore_triggered() {
Database::setLocalIgnored(p->qsHash, ignored);
}

void MainWindow::on_qaUserLocalVolume_triggered() {
ClientUser *p = getContextMenuUser();
if (!p) {
return;
}
openUserLocalVolumeDialog(p);
}

void MainWindow::openUserLocalVolumeDialog(ClientUser *p) {
unsigned int session = p->uiSession;
::UserLocalVolumeDialog *uservol = new ::UserLocalVolumeDialog(this, session);
int res = uservol->exec();
p = ClientUser::get(session);
if (p && ! p->qsHash.isEmpty()) {
Database::setUserLocalVolume(p->qsHash, p->fLocalVolume);
}

delete uservol;
}

void MainWindow::on_qaUserDeaf_triggered() {
ClientUser *p = getContextMenuUser();
if (!p)
@@ -141,6 +141,7 @@ class MainWindow : public QMainWindow, public MessageHandler, public Ui::MainWin

void updateChatBar();
void openTextMessageDialog(ClientUser *p);
void openUserLocalVolumeDialog(ClientUser *p);

#ifdef Q_OS_WIN
#if QT_VERSION >= 0x050000
@@ -211,6 +212,7 @@ class MainWindow : public QMainWindow, public MessageHandler, public Ui::MainWin
void on_qaUserPrioritySpeaker_triggered();
void on_qaUserLocalIgnore_triggered();
void on_qaUserLocalMute_triggered();
void on_qaUserLocalVolume_triggered();
void on_qaUserTextMessage_triggered();
void on_qaUserRegister_triggered();
void on_qaUserInformation_triggered();
@@ -331,6 +331,17 @@
<string>Silently drops all text messages from the user.</string>
</property>
</action>
<action name="qaUserLocalVolume">
<property name="text">
<string>Local Volume Adjustment</string>
</property>
<property name="toolTip">
<string>Locally adjust the user's speech volume.</string>
</property>
<property name="whatsThis">
<string>Opens a dialog with a volume slider. Use this on other users in the same room.</string>
</property>
</action>
<action name="qaUserLocalMute">
<property name="checkable">
<bool>true</bool>
@@ -305,6 +305,7 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) {
pDst->setLocalMute(true);
if (Database::isLocalIgnored(pDst->qsHash))
pDst->setLocalIgnore(true);
pDst->fLocalVolume = Database::getUserLocalVolume(pDst->qsHash);
}

if (bNewUser)
@@ -0,0 +1,58 @@
/* Copyright (C) 2015, Fredrik Nordin <freedick@ludd.ltu.se>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Mumble Developers nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "mumble_pch.hpp"

#include "UserLocalVolumeDialog.h"
#include "Global.h"
#include "ClientUser.h"

UserLocalVolumeDialog::UserLocalVolumeDialog(QWidget *p, unsigned int sessionId)
: QDialog(p)
, m_clientSession(sessionId) {
setupUi(this);
ClientUser *user = ClientUser::get(sessionId);
if (user) {
QString title = tr("Adjusting local volume for %1").arg(user->qsName);
setWindowTitle(title);
qsUserLocalVolume->setValue(round(log2(user->fLocalVolume) * 6.0f));
}
}

void UserLocalVolumeDialog::on_qsUserLocalVolume_valueChanged(int v) {
QString text;
text.sprintf("%+i", v);
qlUserLocalVolume->setText(tr("%1 dB").arg(text));
ClientUser *user = ClientUser::get(m_clientSession);
if (user) {
user->fLocalVolume = pow(2.0f, v / 6.0f); // Decibel formula +6db = *2
}
}

@@ -0,0 +1,48 @@
/* Copyright (C) 2015, Fredrik Nordin <freedick@ludd.ltu.se>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the Mumble Developers nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MUMBLE_MUMBLE_USERVOLUME_H_
#define MUMBLE_MUMBLE_USERVOLUME_H_

#include "ui_UserLocalVolumeDialog.h"
#include "ClientUser.h"

class UserLocalVolumeDialog : public QDialog, public Ui::UserLocalVolumeDialog {
private:
Q_OBJECT
Q_DISABLE_COPY(UserLocalVolumeDialog)
unsigned int m_clientSession;
public slots:
void on_qsUserLocalVolume_valueChanged(int v);
public:
UserLocalVolumeDialog(QWidget *parent = NULL, unsigned int sessionId=0);
};

#endif
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserLocalVolumeDialog</class>
<widget class="QDialog" name="UserLocalVolumeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>45</height>
</rect>
</property>
<layout class="QGridLayout">
<item row="0" column="0">
<widget class="QSlider" name="qsUserLocalVolume">
<property name="toolTip">
<string>Local volume for other users</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Adjust the volume of other users locally&lt;/b&gt;&lt;br /&gt;Mumble supports adjusting the volume of other users locally.</string>
</property>
<property name="minimum">
<number>-30</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="qlUserLocalVolume">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string notr="true">+0 dB</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="qbbButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>qbbButtons</sender>
<signal>accepted()</signal>
<receiver>UserLocalVolumeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>287</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -129,6 +129,7 @@ HEADERS *= BanEditor.h \
ClientUser.h \
UserEdit.h \
UserListModel.h \
UserLocalVolumeDialog.h \
Tokens.h \
UserView.h \
RichTextEditor.h \
@@ -199,6 +200,7 @@ SOURCES *= BanEditor.cpp \
ClientUser.cpp \
UserEdit.cpp \
UserListModel.cpp \
UserLocalVolumeDialog.cpp \
Tokens.cpp \
UserView.cpp \
RichTextEditor.cpp \
@@ -237,6 +239,7 @@ FORMS *= ConfigDialog.ui \
GlobalShortcutTarget.ui \
Cert.ui \
UserEdit.ui \
UserLocalVolumeDialog.ui \
AudioWizard.ui \
Tokens.ui \
RichTextEditor.ui \

0 comments on commit 15f47f4

Please sign in to comment.
You can’t perform that action at this time.