Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT(client, server): Add more control over UDP stream. #5931

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Mumble.proto
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ message UserState {
repeated uint32 listening_channel_remove = 22;
// A list of volume adjustments the user has applied to listeners
repeated VolumeAdjustment listening_volume_adjustment = 23;
// Force the server to send audio packets to the client via TCP only.
// Values: false(Default/Auto-detect), true(UDP disabled)
optional bool disable_udp_mode = 24;
}

// Relays information on the bans. The client may send the BanList message to
Expand Down
2 changes: 1 addition & 1 deletion src/mumble/AudioConfigDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ void AudioInputDialog::updateBitrate() {
overhead = 100 * 8 * (20 + 8 + 4 + 1 + 2 + p);

// TCP is 12 more bytes than UDP
if (NetworkConfig::TcpModeEnabled())
if (NetworkConfig::UdpModeDisabled())
overhead += 100 * 8 * 12;

if (Global::get().s.bTransmitPosition)
Expand Down
2 changes: 1 addition & 1 deletion src/mumble/AudioInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ void AudioInput::setMaxBandwidth(int bitspersec) {

int AudioInput::getNetworkBandwidth(int bitrate, int frames) {
int overhead = 20 + 8 + 4 + 1 + 2 + (Global::get().s.bTransmitPosition ? 12 : 0)
+ (NetworkConfig::TcpModeEnabled() ? 12 : 0) + frames;
+ (NetworkConfig::UdpModeDisabled() ? 12 : 0) + frames;
overhead *= (800 / frames);
int bw = overhead + bitrate;

Expand Down
8 changes: 8 additions & 0 deletions src/mumble/ConfigWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ void ConfigWidget::loadCheckBox(QAbstractButton *c, bool v) {
}
}

void ConfigWidget::loadRadioButton(QAbstractButton *c, bool v) {
if (v != c->isChecked()) {
c->setChecked(v);
} else {
c->toggled(v);
}
}

void ConfigWidget::loadComboBox(QComboBox *c, int v) {
if (c->currentIndex() != v) {
c->setCurrentIndex(v);
Expand Down
2 changes: 2 additions & 0 deletions src/mumble/ConfigWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ class ConfigWidget : public QWidget {
void loadSlider(QSlider *, int);
void loadCheckBox(QAbstractButton *, bool);
void loadComboBox(QComboBox *, int);
void loadRadioButton(QAbstractButton *, bool);
signals:
void intSignal(int);
void boolSignal(bool);

public:
Settings &s;
Expand Down
9 changes: 9 additions & 0 deletions src/mumble/EnumStringConversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@
PROCESS(OverlaySettings::OverlayExclusionMode, WhitelistExclusionMode, "Whitelist") \
PROCESS(OverlaySettings::OverlayExclusionMode, BlacklistExclusionMode, "Blacklist")

#define UDP_MODES \
PROCESS(UDPMode::Mode, Disabled, "Disabled") \
PROCESS(UDPMode::Mode, InboundOnly, "InboundOnly") \
PROCESS(UDPMode::Mode, OutboundOnly, "OutboundOnly") \
PROCESS(UDPMode::Mode, Bidirectional, "Bidirectional")

#define PROCESS_ALL_ENUMS \
BEFORE_CODE(Settings::AudioTransmit) \
Expand Down Expand Up @@ -214,6 +219,9 @@
AFTER_CODE \
BEFORE_CODE(OverlaySettings::OverlayExclusionMode) \
OVERLAY_EXCLUSION_MODE_VALUES \
AFTER_CODE \
BEFORE_CODE(UDPMode::Mode) \
UDP_MODES \
AFTER_CODE


Expand Down Expand Up @@ -275,3 +283,4 @@ PROCESS_ALL_ENUMS
#undef LOOP_MODE_VALUES
#undef VAD_SOURCE_VALUES
#undef AUDIO_TRANSMIT_VALUES
#undef UDP_MODES
2 changes: 2 additions & 0 deletions src/mumble/EnumStringConversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const char *enumToString(OverlaySettings::OverlayPresets e);
const char *enumToString(OverlaySettings::OverlayShow e);
const char *enumToString(OverlaySettings::OverlaySort e);
const char *enumToString(OverlaySettings::OverlayExclusionMode e);
const char *enumToString(UDPMode::Mode e);

namespace details {

Expand All @@ -61,6 +62,7 @@ void stringToEnum(const std::string &str, OverlaySettings::OverlayPresets &e);
void stringToEnum(const std::string &str, OverlaySettings::OverlayShow &e);
void stringToEnum(const std::string &str, OverlaySettings::OverlaySort &e);
void stringToEnum(const std::string &str, OverlaySettings::OverlayExclusionMode &e);
void stringToEnum(const std::string &str, UDPMode::Mode &e);

}; // namespace details

Expand Down
39 changes: 33 additions & 6 deletions src/mumble/NetworkConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "MainWindow.h"
#include "OSInfo.h"
#include "ServerHandler.h"
#include "Global.h"

#include <QSignalBlocker>
Expand Down Expand Up @@ -49,7 +50,13 @@ QIcon NetworkConfig::icon() const {
}

void NetworkConfig::load(const Settings &r) {
loadCheckBox(qcbTcpMode, s.bTCPCompat);
loadCheckBox(qcbUdpModeDisabled, UDPMode::isUdpModeDisabled(s.eUdpMode));
// To make sure we always select one of the radio buttons as the default choice which is "Bidirectional".
loadRadioButton(qrbUdpBidirectional,
UDPMode::isUdpModeBidirectional(s.eUdpMode) || UDPMode::isUdpModeDisabled(s.eUdpMode));
loadRadioButton(qrbUdpIn, UDPMode::isUdpModeInboundOnly(s.eUdpMode));
loadRadioButton(qrbUdpOut, UDPMode::isUdpModeOutboundOnly(s.eUdpMode));
qgbUdpMode->setDisabled(UDPMode::isUdpModeDisabled(s.eUdpMode));
loadCheckBox(qcbQoS, s.bQoS);
loadCheckBox(qcbAutoReconnect, s.bReconnect);
loadCheckBox(qcbAutoConnect, s.bAutoConnect);
Expand Down Expand Up @@ -79,7 +86,18 @@ void NetworkConfig::load(const Settings &r) {
}

void NetworkConfig::save() const {
s.bTCPCompat = qcbTcpMode->isChecked();
s.bUdpDisabled = qcbUdpModeDisabled->isChecked();
s.eUdpMode =
(qcbUdpModeDisabled->isChecked()
? UDPMode::Disabled
: (qrbUdpIn->isChecked() ? UDPMode::InboundOnly
: (qrbUdpOut->isChecked() ? UDPMode::OutboundOnly : UDPMode::Bidirectional)));
qgbUdpMode->setDisabled(UDPMode::isUdpModeDisabled(s.eUdpMode));
if (Global::get().sh) {
Global::get().sh->disableUdpMode(UDPMode::isUdpModeDisabled(s.eUdpMode)
|| UDPMode::isUdpModeOutboundOnly(s.eUdpMode));
}

s.bQoS = qcbQoS->isChecked();
s.bReconnect = qcbAutoReconnect->isChecked();
s.bAutoConnect = qcbAutoConnect->isChecked();
Expand Down Expand Up @@ -122,9 +140,10 @@ void NetworkConfig::SetupProxy() {
QNetworkProxy::setApplicationProxy(proxy);
}

bool NetworkConfig::TcpModeEnabled() {
bool NetworkConfig::UdpModeDisabled() {
/*
* We force TCP mode for both HTTP and SOCKS5 proxies, even though SOCKS5 supports UDP.
* We force TCP mode by disabling UDP mode completely for both HTTP and SOCKS5 proxies,
* even though SOCKS5 supports UDP.
*
* This is because Qt's automatic application-wide proxying fails when we're in UDP
* mode since the datagram transmission code assumes that its socket is created in its
Expand All @@ -138,7 +157,11 @@ bool NetworkConfig::TcpModeEnabled() {
* itself already is a potential latency killer.
*/

return Global::get().s.ptProxyType != Settings::NoProxy || Global::get().s.bTCPCompat;
return Global::get().s.ptProxyType != Settings::NoProxy || UDPMode::isUdpModeDisabled(Global::get().s.eUdpMode);
}

bool NetworkConfig::canSendTcpMessage() {
return (UdpModeDisabled() || UDPMode::isUdpModeInboundOnly(Global::get().s.eUdpMode));
}

void NetworkConfig::accept() const {
Expand All @@ -152,11 +175,15 @@ void NetworkConfig::on_qcbType_currentIndexChanged(int v) {
qlePort->setEnabled(pt != Settings::NoProxy);
qleUsername->setEnabled(pt != Settings::NoProxy);
qlePassword->setEnabled(pt != Settings::NoProxy);
qcbTcpMode->setEnabled(pt == Settings::NoProxy);
qcbUdpModeDisabled->setEnabled(pt == Settings::NoProxy);

s.ptProxyType = pt;
}

void NetworkConfig::on_qcbUdpModeDisabled_stateChanged(int v) {
qgbUdpMode->setDisabled(v != 0);
}

#ifdef NO_UPDATE_CHECK
void NetworkConfig::on_qcbAutoUpdate_stateChanged(int state) {
if (state == Qt::Checked) {
Expand Down
4 changes: 3 additions & 1 deletion src/mumble/NetworkConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ class NetworkConfig : public ConfigWidget, Ui::NetworkConfig {
virtual const QString &getName() const Q_DECL_OVERRIDE;
virtual QIcon icon() const Q_DECL_OVERRIDE;
static void SetupProxy();
static bool TcpModeEnabled();
static bool UdpModeDisabled();
static bool canSendTcpMessage();
public slots:
void accept() const Q_DECL_OVERRIDE;
void save() const Q_DECL_OVERRIDE;
void load(const Settings &r) Q_DECL_OVERRIDE;

void on_qcbType_currentIndexChanged(int v);
void on_qcbUdpModeDisabled_stateChanged(int v);
#ifdef NO_UPDATE_CHECK
void on_qcbAutoUpdate_stateChanged(int state);
#endif
Expand Down
69 changes: 65 additions & 4 deletions src/mumble/NetworkConfig.ui
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,79 @@
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="qcbTcpMode">
<widget class="QCheckBox" name="qcbUdpModeDisabled">
<property name="toolTip">
<string>Use TCP compatibility mode</string>
<string>Disable UDP mode completely</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Enable TCP compatibility mode&lt;/b&gt;.&lt;br /&gt;This will make Mumble use only TCP when communicating with the server. This will increase overhead and cause lost packets to produce noticeable pauses in communication, so this should only be used if you are unable to use the default (which uses UDP for voice and TCP for control).</string>
<string>&lt;b&gt;Disable UDP mode&lt;/b&gt;.&lt;br /&gt;This will make Mumble use only TCP when communicating with the server. This will increase overhead and cause lost packets to produce noticeable pauses in communication, so this should only be used if you are unable to use the default (which uses UDP for voice and TCP for control).</string>
</property>
<property name="text">
<string>Force TCP mode</string>
<string>Disable UDP mode</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="qgbUdpMode">
<property name="title">
<string>UDP stream mode</string>
</property>
<layout class="QHBoxLayout">
<item>
<widget class="QRadioButton" name="qrbUdpIn">
<property name="toolTip">
<string>Inbound stream is UDP and outbound is TCP.</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Inbound stream is UDP and outbound is TCP.&lt;</string>
</property>
<property name="text">
<string>Inbound only</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="qrbUdpOut">
<property name="toolTip">
<string>Outbound stream is UDP and inbound is TCP.</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Outbound stream is UDP and inbound is TCP.&lt;b&gt;</string>
</property>
<property name="text">
<string>Outbound only</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="qrbUdpBidirectional">
<property name="toolTip">
<string>Both inbound and outbound stream is UDP.</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Both inbound and outbound stream is UDP.&lt;b&gt;</string>
</property>
<property name="text">
<string>Bidirectional</string>
</property>
</widget>
</item>
<!-- <item>
<widget class="QRadioButton" name="qrbUdpAuto">
<property name="toolTip">
<string>Auto mode(Disable user controlled UDP stream mode)</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;Auto mode(Disable user controlled UDP stream mode).&lt;b&gt;</string>
</property>
<property name="text">
<string>Disabled(Auto)</string>
</property>
</widget>
</item> -->
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="qcbQoS">
<property name="toolTip">
Expand Down
18 changes: 14 additions & 4 deletions src/mumble/ServerHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ void ServerHandler::sendMessage(const unsigned char *data, int len, bool force)
if (!connection || !connection->csCrypt->isValid())
return;

if (!force && (NetworkConfig::TcpModeEnabled() || !bUdp)) {
if (!force && NetworkConfig::canSendTcpMessage()) {
QByteArray qba;

qba.resize(len + 6);
Expand Down Expand Up @@ -580,7 +580,7 @@ void ServerHandler::sendPingInternal() {

quint64 t = tTimestamp.elapsed();

if (qusUdp) {
if (qusUdp && !NetworkConfig::UdpModeDisabled()) {
Mumble::Protocol::PingData pingData;
pingData.timestamp = t;
pingData.requestAdditionalInformation = false;
Expand Down Expand Up @@ -651,7 +651,7 @@ void ServerHandler::message(Mumble::Protocol::TCPMessageType type, const QByteAr
if (((connection->csCrypt->uiRemoteGood == 0) || (connection->csCrypt->uiGood == 0)) && bUdp
&& (tTimestamp.elapsed() > 20000000ULL)) {
bUdp = false;
if (!NetworkConfig::TcpModeEnabled()) {
if (!NetworkConfig::UdpModeDisabled()) {
if ((connection->csCrypt->uiRemoteGood == 0) && (connection->csCrypt->uiGood == 0))
Global::get().mw->msgBox(
tr("UDP packets cannot be sent to or received from the server. Switching to TCP mode."));
Expand All @@ -666,7 +666,7 @@ void ServerHandler::message(Mumble::Protocol::TCPMessageType type, const QByteAr
}
} else if (!bUdp && (connection->csCrypt->uiRemoteGood > 3) && (connection->csCrypt->uiGood > 3)) {
bUdp = true;
if (!NetworkConfig::TcpModeEnabled()) {
if (!NetworkConfig::UdpModeDisabled()) {
Global::get().mw->msgBox(
tr("UDP packets can be sent to and received from the server. Switching back to UDP mode."));

Expand Down Expand Up @@ -799,6 +799,10 @@ void ServerHandler::serverConnectionConnected() {
mpa.set_opus(true);
sendMessage(mpa);

if (UDPMode::isUdpModeDisabled(Global::get().s.eUdpMode)) {
disableUdpMode(true);
}

{
QMutexLocker qml(&qmUdp);

Expand Down Expand Up @@ -1128,6 +1132,12 @@ void ServerHandler::announceRecordingState(bool recording) {
sendMessage(mpus);
}

void ServerHandler::disableUdpMode(bool value) {
MumbleProto::UserState mpus;
mpus.set_disable_udp_mode(value);
sendMessage(mpus);
}

QUrl ServerHandler::getServerURL(bool withPassword) const {
QUrl url;

Expand Down
1 change: 1 addition & 0 deletions src/mumble/ServerHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class ServerHandler : public QThread {
void requestChannelPermissions(unsigned int channel);
void setSelfMuteDeafState(bool mute, bool deaf);
void announceRecordingState(bool recording);
void disableUdpMode(bool value);

/// Return connection information as a URL
QUrl getServerURL(bool withPassword = false) const;
Expand Down
2 changes: 1 addition & 1 deletion src/mumble/ServerInformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void ServerInformation::updateConnectionDetails() {
}

// UDP
if (NetworkConfig::TcpModeEnabled()) {
if (NetworkConfig::UdpModeDisabled()) {
connection_udp_infoMessage->show();

connection_udp_encryption->hide();
Expand Down
3 changes: 1 addition & 2 deletions src/mumble/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ void Settings::save(const QString &path) const {
{
// The separate scope makes sure, the stream is closed again after the write has finished
std::ofstream stream(tmpFile.fileName().toUtf8());

stream << settingsJSON.dump(4) << std::endl;
}

Expand Down Expand Up @@ -921,7 +920,7 @@ void Settings::legacyLoad(const QString &path) {
LOAD(qsTTSLanguage, "tts/language");

// Network settings
LOAD(bTCPCompat, "net/tcponly");
LOAD(bUdpDisabled, "net/tcponly");
LOAD(bQoS, "net/qos");
LOAD(bReconnect, "net/reconnect");
LOAD(bAutoConnect, "net/autoconnect");
Expand Down