From e502c53b2773ac052cd87c753a48406b584b36bf Mon Sep 17 00:00:00 2001 From: Hartmnt Date: Mon, 6 Jan 2025 16:24:58 +0000 Subject: [PATCH] FEAT(server, client): Add rolling connection quality stats Previously, only the total packet statistics since the user had connected were tracked. While a good start, these stats are not really helping to understand sudden connection problems. This commit adds additional server-side rolling packet stats which are updated every few seconds/minutes. These new stats are sent using additional fields in the UserStats protocol message and rendered in the UserInformation dialog in the client. Closes #5872 --- src/CMakeLists.txt | 1 + src/Mumble.proto | 7 + src/crypto/CryptState.cpp | 49 +++++ src/crypto/CryptState.h | 26 ++- src/crypto/CryptStateOCB2.cpp | 1 + src/mumble/UserInformation.cpp | 68 ++++++- src/mumble/UserInformation.ui | 354 ++++++++++++++++++++++++--------- src/murmur/Messages.cpp | 14 ++ 8 files changed, 418 insertions(+), 102 deletions(-) create mode 100644 src/crypto/CryptState.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c73ee08c3b..434a6cb94de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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" diff --git a/src/Mumble.proto b/src/Mumble.proto index 169c18a6925..1b26ac342a8 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -553,6 +553,13 @@ message UserStats { // True if the user has a strong certificate. optional bool strong_certificate = 18 [default = false]; optional bool opus = 19 [default = false]; + + // Rolling packet statistics time window as defined on the server. + optional uint32 rolling_time_window = 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 diff --git a/src/crypto/CryptState.cpp b/src/crypto/CryptState.cpp new file mode 100644 index 00000000000..c30bed5936a --- /dev/null +++ b/src/crypto/CryptState.cpp @@ -0,0 +1,49 @@ +// 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 . + +#include "CryptState.h" + +void CryptState::updateRollingStats() { + std::chrono::time_point< std::chrono::steady_clock > now = std::chrono::steady_clock::now(); + + // Update no more than every few seconds + if ((now - m_rollingLastSampleTime) < m_rollingScanInterval) { + return; + } + + m_rollingLastSampleTime = now; + + PacketStatsSnapshot snapshotLocal; + snapshotLocal.stats = m_statsLocal; + snapshotLocal.timestamp = now; + m_statsLocalReference.push(snapshotLocal); + + PacketStatsSnapshot snapshotRemote; + snapshotRemote.stats = m_statsRemote; + snapshotRemote.timestamp = now; + m_statsRemoteReference.push(snapshotRemote); + + while (!m_statsLocalReference.empty() && (now - m_statsLocalReference.front().timestamp) > m_rollingWindow) { + m_statsLocalReference.pop(); + } + + while (!m_statsRemoteReference.empty() && (now - m_statsRemoteReference.front().timestamp) > m_rollingWindow) { + m_statsRemoteReference.pop(); + } + + if (!m_statsLocalReference.empty()) { + m_statsLocalRolling.good = m_statsLocal.good - m_statsLocalReference.front().stats.good; + m_statsLocalRolling.late = m_statsLocal.late - m_statsLocalReference.front().stats.late; + m_statsLocalRolling.lost = m_statsLocal.lost - m_statsLocalReference.front().stats.lost; + m_statsLocalRolling.resync = m_statsLocal.resync - m_statsLocalReference.front().stats.resync; + } + + if (!m_statsRemoteReference.empty()) { + m_statsRemoteRolling.good = m_statsRemote.good - m_statsRemoteReference.front().stats.good; + m_statsRemoteRolling.late = m_statsRemote.late - m_statsRemoteReference.front().stats.late; + m_statsRemoteRolling.lost = m_statsRemote.lost - m_statsRemoteReference.front().stats.lost; + m_statsRemoteRolling.resync = m_statsRemote.resync - m_statsRemoteReference.front().stats.resync; + } +} diff --git a/src/crypto/CryptState.h b/src/crypto/CryptState.h index aa2483a6d70..c2851bee052 100644 --- a/src/crypto/CryptState.h +++ b/src/crypto/CryptState.h @@ -7,6 +7,8 @@ #define MUMBLE_CRYPTSTATE_H_ #include "Timer.h" +#include +#include #include struct PacketStats { @@ -16,12 +18,32 @@ struct PacketStats { unsigned int resync = 0; }; +struct PacketStatsSnapshot { + PacketStats stats; + std::chrono::time_point< std::chrono::steady_clock > timestamp; +}; + class CryptState { private: Q_DISABLE_COPY(CryptState) + + const std::chrono::seconds m_rollingScanInterval = std::chrono::seconds(5); + std::chrono::time_point< std::chrono::steady_clock > m_rollingLastSampleTime = {}; + + std::queue< PacketStatsSnapshot > m_statsLocalReference; + std::queue< PacketStatsSnapshot > m_statsRemoteReference; + +protected: + void updateRollingStats(); + public: - PacketStats m_statsLocal = {}; - PacketStats m_statsRemote = {}; + PacketStats m_statsLocal = {}; + PacketStats m_statsRemote = {}; + PacketStats m_statsLocalRolling = {}; + PacketStats m_statsRemoteRolling = {}; + + /// This is the packet statistics sliding time window size in seconds + std::chrono::seconds m_rollingWindow = std::chrono::minutes(5); Timer tLastGood; Timer tLastRequest; diff --git a/src/crypto/CryptStateOCB2.cpp b/src/crypto/CryptStateOCB2.cpp index 733ee12a4da..55447f6f4ff 100644 --- a/src/crypto/CryptStateOCB2.cpp +++ b/src/crypto/CryptStateOCB2.cpp @@ -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)); } + updateRollingStats(); tLastGood.restart(); return true; } diff --git a/src/mumble/UserInformation.cpp b/src/mumble/UserInformation.cpp index a735763f319..40be128fb23 100644 --- a/src/mumble/UserInformation.cpp +++ b/src/mumble/UserInformation.cpp @@ -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_window() && 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())); @@ -179,17 +183,65 @@ void UserInformation::update(const MumbleProto::UserStats &msg) { quint32 allFromPackets = from.good() + from.late() + from.lost(); qlFromLatePercent->setText( - QString::number(allFromPackets > 0 ? from.late() * 100.0 / allFromPackets : 0., 'f', 2)); + QString::number(allFromPackets > 0 ? from.late() * 100.0 / allFromPackets : 0., 'f', 1)); qlFromLostPercent->setText( - QString::number(allFromPackets > 0 ? from.lost() * 100.0 / allFromPackets : 0., 'f', 2)); + QString::number(allFromPackets > 0 ? from.lost() * 100.0 / allFromPackets : 0., 'f', 1)); 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); + qlToLatePercent->setText(QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 1)); + qlToLostPercent->setText(QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 1)); } + 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', 1)); + qlFromLostPercentRolling->setText( + QString::number(allFromPackets > 0 ? from.lost() * 100.0 / allFromPackets : 0., 'f', 1)); + + quint32 allToPackets = to.good() + to.late() + to.lost(); + qlToLatePercentRolling->setText( + QString::number(allToPackets > 0 ? to.late() * 100.0 / allToPackets : 0., 'f', 1)); + qlToLostPercentRolling->setText( + QString::number(allToPackets > 0 ? to.lost() * 100.0 / allToPackets : 0., 'f', 1)); + + uint32_t rollingSeconds = msg.rolling_time_window(); + 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"))); + } + } + + qlFromGoodRolling->setVisible(hasRollingStats); + qlFromLateRolling->setVisible(hasRollingStats); + qlFromLostRolling->setVisible(hasRollingStats); + qlFromResyncRolling->setVisible(hasRollingStats); + qlToGoodRolling->setVisible(hasRollingStats); + qlToLateRolling->setVisible(hasRollingStats); + qlToLostRolling->setVisible(hasRollingStats); + qlToResyncRolling->setVisible(hasRollingStats); + qlFromLatePercentRolling->setVisible(hasRollingStats); + qlFromLostPercentRolling->setVisible(hasRollingStats); + qlToLatePercentRolling->setVisible(hasRollingStats); + qlToLostPercentRolling->setVisible(hasRollingStats); + qliRolling->setVisible(hasRollingStats); + qliRollingFrom->setVisible(hasRollingStats); + qliRollingTo->setVisible(hasRollingStats); + if (msg.has_onlinesecs()) { if (msg.has_idlesecs()) qlTime->setText( diff --git a/src/mumble/UserInformation.ui b/src/mumble/UserInformation.ui index 54c8374f8c3..c3a12c580e1 100644 --- a/src/mumble/UserInformation.ui +++ b/src/mumble/UserInformation.ui @@ -7,7 +7,7 @@ 0 0 488 - 658 + 713 @@ -39,10 +39,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -94,7 +94,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -110,10 +110,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -165,10 +165,10 @@ - Qt::PlainText + Qt::TextFormat::PlainText - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -194,7 +194,7 @@ Pings received - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -204,7 +204,7 @@ Average ping - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -214,7 +214,7 @@ Ping deviation - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -231,10 +231,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -244,10 +244,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -257,10 +257,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -277,10 +277,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -290,10 +290,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -303,10 +303,10 @@ - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -319,13 +319,33 @@ UDP Network statistics + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + to client rolling average + + + To Client + + + Good - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -335,145 +355,277 @@ Late - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Lost + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Resync + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - From Client + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + + + Lost + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - + To Client + + + + + true + + + + Last X minutes: + + + + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + - + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + % + + + % lost + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + from client rolling average + + + From Client + + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + Resync + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -482,58 +634,76 @@ % + + % late + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - % + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse - - + + - + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - + + - + From Client - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + Total: - - + + - + - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -565,7 +735,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -588,7 +758,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index 8d0dc3abd2a..0f3778f8292 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -2285,6 +2285,20 @@ void Server::msgUserStats(ServerUser *uSource, MumbleProto::UserStats &msg) { mpusss->set_late(pDstServerUser->csCrypt->m_statsRemote.late); mpusss->set_lost(pDstServerUser->csCrypt->m_statsRemote.lost); mpusss->set_resync(pDstServerUser->csCrypt->m_statsRemote.resync); + + mpusss = msg.mutable_rolling_from_client(); + mpusss->set_good(pDstServerUser->csCrypt->m_statsLocalRolling.good); + mpusss->set_late(pDstServerUser->csCrypt->m_statsLocalRolling.late); + mpusss->set_lost(pDstServerUser->csCrypt->m_statsLocalRolling.lost); + mpusss->set_resync(pDstServerUser->csCrypt->m_statsLocalRolling.resync); + + mpusss = msg.mutable_rolling_from_server(); + mpusss->set_good(pDstServerUser->csCrypt->m_statsRemoteRolling.good); + mpusss->set_late(pDstServerUser->csCrypt->m_statsRemoteRolling.late); + mpusss->set_lost(pDstServerUser->csCrypt->m_statsRemoteRolling.lost); + mpusss->set_resync(pDstServerUser->csCrypt->m_statsRemoteRolling.resync); + + msg.set_rolling_time_window(pDstServerUser->csCrypt->m_rollingWindow.count()); } msg.set_udp_packets(pDstServerUser->uiUDPPackets);