Skip to content

Commit

Permalink
FEAT(client): Add rolling connection quality information
Browse files Browse the repository at this point in the history
  • Loading branch information
Hartmnt committed Jan 6, 2025
1 parent ecea27b commit db6979c
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 101 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ set(SHARED_SOURCES

"crypto/CryptographicHash.cpp"
"crypto/CryptographicRandom.cpp"
"crypto/CryptState.cpp"
"crypto/CryptStateOCB2.cpp"

"${3RDPARTY_DIR}/arc4random/arc4random_uniform.cpp"
Expand Down
6 changes: 6 additions & 0 deletions src/Mumble.proto
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,12 @@ message UserStats {
// True if the user has a strong certificate.
optional bool strong_certificate = 18 [default = false];
optional bool opus = 19 [default = false];

optional uint32 rolling_time = 20;
// Rolling packet statistics for packets received from the client.
optional Stats rolling_from_client = 21;
// Rolling packet statistics for packets sent by the server.
optional Stats rolling_from_server = 22;
}

// Used by the client to request binary data from the server. By default large
Expand Down
38 changes: 38 additions & 0 deletions src/crypto/CryptState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 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 "CryptState.h"

void CryptState::handleRollingStats() {
// Update every 5 seconds
if (!m_rollingTimer.isElapsed(1000000ULL * 5ULL)) {
return;
}

m_rollingTimer.restart();

m_statsLocalReference.push(m_statsLocalRolling);
m_statsRemoteReference.push(m_statsRemoteRolling);

uint32_t maxEntries = m_rollingInterval / 5;

while (m_statsLocalReference.size() > maxEntries) {
m_statsLocalReference.pop();
}

while (m_statsRemoteReference.size() > maxEntries) {
m_statsRemoteReference.pop();
}

m_statsLocalRolling.good = m_statsLocal.good - m_statsLocalReference.front().good;
m_statsLocalRolling.late = m_statsLocal.late - m_statsLocalReference.front().late;
m_statsLocalRolling.lost = m_statsLocal.lost - m_statsLocalReference.front().lost;
m_statsLocalRolling.resync = m_statsLocal.resync - m_statsLocalReference.front().resync;

m_statsRemoteRolling.good = m_statsRemote.good - m_statsRemoteReference.front().good;
m_statsRemoteRolling.late = m_statsRemote.late - m_statsRemoteReference.front().late;
m_statsRemoteRolling.lost = m_statsRemote.lost - m_statsRemoteReference.front().lost;
m_statsRemoteRolling.resync = m_statsRemote.resync - m_statsRemoteReference.front().resync;
}
20 changes: 17 additions & 3 deletions src/crypto/CryptState.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,35 @@
#define MUMBLE_CRYPTSTATE_H_

#include "Timer.h"
#include <queue>
#include <string>

struct PacketStats {
unsigned int good = 0;
unsigned int late = 0;
unsigned int lost = 0;
unsigned int rsync = 0;
unsigned int rseync = 0;
};

class CryptState {
private:
Q_DISABLE_COPY(CryptState)

Timer m_rollingTimer;

std::queue< PacketStats > m_statsLocalReference;
std::queue< PacketStats > m_statsRemoteReference;

protected:
void handleRollingStats();

public:
PacketStats m_statsLocal = {};
PacketStats m_statsRemote = {};
PacketStats m_statsLocal = {};
PacketStats m_statsRemote = {};
PacketStats m_statsLocalRolling = {};
PacketStats m_statsRemoteRolling = {};

uint32_t m_rollingInterval = 60 * 5;

Timer tLastGood;
Timer tLastRequest;
Expand Down
1 change: 1 addition & 0 deletions src/crypto/CryptStateOCB2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ bool CryptStateOCB2::decrypt(const unsigned char *source, unsigned char *dst, un
m_statsLocal.lost -= static_cast< unsigned int >(std::abs(lost));
}

handleRollingStats();
tLastGood.restart();
return true;
}
Expand Down
44 changes: 40 additions & 4 deletions src/mumble/UserInformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@ void UserInformation::update(const MumbleProto::UserStats &msg) {
qlTCPVar->setText(QString::number(msg.tcp_ping_var() > 0.0f ? sqrtf(msg.tcp_ping_var()) : 0.0f, 'f', 2));
qlUDPVar->setText(QString::number(msg.udp_ping_var() > 0.0f ? sqrtf(msg.udp_ping_var()) : 0.0f, 'f', 2));

if (msg.has_from_client() && msg.has_from_server()) {
qgbUDP->setVisible(true);
bool hasTotalStats = msg.has_from_client() && msg.has_from_server();
bool hasRollingStats = msg.has_rolling_time() && msg.has_rolling_from_client() && msg.has_rolling_from_server();

qgbUDP->setVisible(hasTotalStats || hasRollingStats);

if (hasTotalStats) {
const MumbleProto::UserStats_Stats &from = msg.from_client();
qlFromGood->setText(QString::number(from.good()));
qlFromLate->setText(QString::number(from.late()));
Expand All @@ -186,8 +190,40 @@ void UserInformation::update(const MumbleProto::UserStats &msg) {
quint32 allToPackets = to.good() + to.late() + to.lost();
qlToLatePercent->setText(QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 2));
qlToLostPercent->setText(QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 2));
} else {
qgbUDP->setVisible(false);
}

if (hasRollingStats) {
const MumbleProto::UserStats_Stats &from = msg.rolling_from_client();
qlFromGoodRolling->setText(QString::number(from.good()));
qlFromLateRolling->setText(QString::number(from.late()));
qlFromLostRolling->setText(QString::number(from.lost()));
qlFromResyncRolling->setText(QString::number(from.resync()));

const MumbleProto::UserStats_Stats &to = msg.rolling_from_server();
qlToGoodRolling->setText(QString::number(to.good()));
qlToLateRolling->setText(QString::number(to.late()));
qlToLostRolling->setText(QString::number(to.lost()));
qlToResyncRolling->setText(QString::number(to.resync()));

quint32 allFromPackets = from.good() + from.late() + from.lost();
qlFromLatePercentRolling->setText(
QString::number(allFromPackets > 0 ? from.late() * 100.0 / allFromPackets : 0., 'f', 2));
qlFromLostPercentRolling->setText(
QString::number(allFromPackets > 0 ? from.lost() * 100.0 / allFromPackets : 0., 'f', 2));

quint32 allToPackets = to.good() + to.late() + to.lost();
qlToLatePercentRolling->setText(
QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 2));
qlToLostPercentRolling->setText(
QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 2));

uint32_t rollingSeconds = msg.rolling_time();
QString rollingText = tr("Last %1 %2:");
if (rollingSeconds < 120) {
qliRolling->setText(rollingText.arg(QString::number(rollingSeconds)).arg(tr("seconds")));
} else {
qliRolling->setText(rollingText.arg(QString::number(rollingSeconds / 60)).arg(tr("minutes")));
}
}

if (msg.has_onlinesecs()) {
Expand Down
Loading

0 comments on commit db6979c

Please sign in to comment.