encrypt overhead fix (33→36, noencrypt_len), mtu default 1280, connmonitor window, total_decrypted for TCP, check.sh

This commit is contained in:
evgeny committed 2026-08-08 16:56:32 +03:00
1 parent 9846599086
commit ca176e1f24
41 files changed
+643 -91

No files matched your search

+2 -2
View File
@@ -16,7 +16,7 @@ AnimTimer *AnimTimer::instance() {
void AnimTimer::shutdown() {
instance()->m_timer.stop();
instance()->m_icons.clear();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "AnimTimer: shutdown");
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "AnimTimer: shutdown");
}
void AnimTimer::registerIcon(const QString &key, LottieIcon *icon) {
@@ -53,7 +53,7 @@ void AnimTimer::onTimer() {
void AnimTimer::logRegisteredIcons() const {
for (auto it = m_icons.constBegin(); it != m_icons.constEnd(); ++it) {
LottieIcon *icon = it.value();
GUI_INFO("LottieIcon: path=%s frames=%d size=%dx%d tgsSize=%d valid=%d",
GUI_DEBUG("LottieIcon: path=%s frames=%d size=%dx%d tgsSize=%d valid=%d",
qPrintable(it.key()), icon->frameCount(),
icon->originalSize().width(), icon->originalSize().height(),
icon->tgsSize(), (int)icon->isValid());
@@ -236,7 +236,7 @@ void AudioDeviceSettingsPage::applyAndSave() {
m_savedCompressorEnabled = compEnabled;
m_savedCompressorMaxGainDb = compMaxGain;
m_savedCompressorRiseRate = compRiseRate;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "saved output=%d input=%d codec=%d compressor=%d gain=%ddB rise=%.1fx",
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "saved output=%d input=%d codec=%d compressor=%d gain=%ddB rise=%.1fx",
outIdx, inIdx, codecPreset, compEnabled, compMaxGain, (float)compRiseRate);
if (m_recorder) {
+4 -4
View File
@@ -78,7 +78,7 @@ bool AudioRecorder::init() {
m_device = new ma_device;
std::memset(m_device, 0, sizeof(*m_device));
m_initialized = true;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "initialized (sampleRate=%d, channels=%d)", m_sampleRate, m_channels);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "initialized (sampleRate=%d, channels=%d)", m_sampleRate, m_channels);
return true;
}
@@ -91,7 +91,7 @@ void AudioRecorder::shutdown() {
}
if (m_device) { delete m_device; m_device = nullptr; }
m_initialized = false;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "shutdown");
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "shutdown");
}
void AudioRecorder::startRecording() {
@@ -122,7 +122,7 @@ void AudioRecorder::startRecording() {
ma_result r = ma_context_get_devices(ctx, nullptr, nullptr, &pCaptureDevices, &captureCount);
if (r == MA_SUCCESS && (ma_uint32)m_captureDeviceIndex < captureCount) {
config.capture.pDeviceID = &pCaptureDevices[m_captureDeviceIndex].id;
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "using capture device[%d]: %s", m_captureDeviceIndex,
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "using capture device[%d]: %s", m_captureDeviceIndex,
pCaptureDevices[m_captureDeviceIndex].name);
}
}
@@ -196,5 +196,5 @@ size_t AudioRecorder::bufferSize() const {
void AudioRecorder::setCompressorEnabled(bool enabled) {
m_compressorEnabled = enabled;
if (m_compressor) audio_compressor_set_enabled(m_compressor, enabled);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "compressor %s", enabled ? "enabled" : "disabled");
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "compressor %s", enabled ? "enabled" : "disabled");
}
+11 -2
View File
@@ -155,6 +155,15 @@ ChannelList::ChannelList(DbManager* db, QWidget *parent)
connect(gearBtn, &QPushButton::clicked, this, [this] { emit settingsRequested(); });
auto *monitorBtn = new QPushButton(QString::fromUtf8("\xF0\x9F\x94\x8D"), footer); /* 🔍 */
monitorBtn->setFixedSize(28, 28);
monitorBtn->setToolTip(QString::fromUtf8("Connection Monitor"));
monitorBtn->setStyleSheet(
"QPushButton { border: none; font-size: 16px; background: transparent; color: gray; }"
"QPushButton:hover { color: palette(text); }");
fl->addWidget(monitorBtn);
connect(monitorBtn, &QPushButton::clicked, this, [this] { emit connMonitorRequested(); });
fl->addStretch();
auto *createBtn = new QPushButton("GRP", footer);
@@ -222,7 +231,7 @@ void ChannelList::loadChannels() {
item->setData(ch.lastMsgAt, ChannelLastMsgAtRole);
item->setData(makeChannelIcon(colors[ci % 6], letter), ChannelIconRole);
m_model->appendRow(item);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "ChannelList::loadChannels row=%d cid='%s' name='%s' unread=%d lastMsgAt=%lld",
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "ChannelList::loadChannels row=%d cid='%s' name='%s' unread=%d lastMsgAt=%lld",
m_model->rowCount()-1, qPrintable(ch.channelId), qPrintable(ch.name), ch.unreadCount,
(long long)ch.lastMsgAt);
ci++;
@@ -266,7 +275,7 @@ void ChannelList::setChannelPeersOnline(const QString& channelId, int count) {
}
}
if (!found)
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, " NOT FOUND in model");
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, " NOT FOUND in model");
}
void ChannelList::setAutoConnectActive(bool active) {
+1
View File
@@ -27,6 +27,7 @@ signals:
void joinRequested();
void createGroupRequested();
void settingsRequested();
void connMonitorRequested();
private:
QListView *m_listView;
+189
View File
@@ -0,0 +1,189 @@
// connmonitorwindow.cpp — ETCP connection monitor (standalone, non-modal window)
#include "connmonitorwindow.h"
#include "../transport/gui_bridge.h"
extern "C" {
#include "chat/chat_core.h"
#include "../../lib/mem.h"
}
#include <QVBoxLayout>
#include <QSplitter>
#include <QLabel>
#include <QFont>
#include <QScrollBar>
#include <QHash>
#include <QApplication>
#include <cstring>
#define CONN_LIST_ENTRY_SIZE 46
static ConnMonitorWindow* g_activeConnMonitor = nullptr;
static void connListCb(const uint8_t* data, int len) {
if (g_activeConnMonitor) g_activeConnMonitor->onConnList(data, len);
}
static void connMetricsCb(const uint8_t* data, int len) {
if (g_activeConnMonitor) g_activeConnMonitor->onConnMetrics(data, len);
}
ConnMonitorWindow::ConnMonitorWindow(QWidget* parent)
: QDialog(parent)
{
setWindowTitle("Connection Monitor");
resize(900, 550);
setAttribute(Qt::WA_DeleteOnClose);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
auto* mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(4);
mainLayout->setContentsMargins(8, 8, 8, 8);
auto* title = new QLabel("Active ETCP Connections (10 fps)", this);
title->setStyleSheet("font-weight: bold; font-size: 13px;");
mainLayout->addWidget(title);
auto* splitter = new QSplitter(Qt::Horizontal, this);
splitter->setStyleSheet(
"QSplitter::handle { background: palette(mid); width: 2px; }");
m_connList = new QListWidget(splitter);
m_connList->setFixedWidth(280);
m_connList->setFont(QFont("monospace", 9));
m_connList->setStyleSheet(
"QListWidget { border: 1px solid palette(mid); border-radius: 4px;"
" background: palette(base); }"
"QListWidget::item { padding: 4px 6px; }"
"QListWidget::item:selected { background: #3390EC; color: white; }");
m_details = new QPlainTextEdit(splitter);
m_details->setReadOnly(true);
m_details->setFont(QFont("monospace", 9));
m_details->setStyleSheet(
"QPlainTextEdit { border: 1px solid palette(mid); border-radius: 4px;"
" padding: 8px; background: palette(base); }");
m_details->setPlaceholderText("Select a connection to view metrics");
splitter->addWidget(m_connList);
splitter->addWidget(m_details);
splitter->setStretchFactor(0, 0);
splitter->setStretchFactor(1, 1);
mainLayout->addWidget(splitter, 1);
m_timer = new QTimer(this);
m_timer->setInterval(100);
connect(m_timer, &QTimer::timeout, this, &ConnMonitorWindow::onTimerTick);
connect(m_connList, &QListWidget::currentItemChanged,
this, &ConnMonitorWindow::onConnSelected);
g_activeConnMonitor = this;
gui_bridge_set_conn_list_cb(connListCb);
gui_bridge_set_conn_metrics_cb(connMetricsCb);
m_timer->start();
}
ConnMonitorWindow::~ConnMonitorWindow() {
m_timer->stop();
if (g_activeConnMonitor == this) g_activeConnMonitor = nullptr;
}
void ConnMonitorWindow::showEvent(QShowEvent* event) {
QDialog::showEvent(event);
m_timer->start();
}
void ConnMonitorWindow::hideEvent(QHideEvent* event) {
m_timer->stop();
QDialog::hideEvent(event);
}
void ConnMonitorWindow::onTimerTick() {
if (m_details->textCursor().hasSelection()) return;
if (QApplication::mouseButtons()) return;
gui_bridge_post_uasync_fn(chat_core_collect_conn_list_trampoline, nullptr);
if (m_selectedNodeId) requestMetricsForSelected();
}
void ConnMonitorWindow::onConnSelected(QListWidgetItem* current, QListWidgetItem* previous) {
(void)previous;
if (!current) { m_selectedNodeId = 0; m_details->clear(); return; }
m_selectedNodeId = (uint64_t)current->data(Qt::UserRole).toULongLong();
requestMetricsForSelected();
}
void ConnMonitorWindow::requestMetricsForSelected() {
void* arg = u_malloc(sizeof(uint64_t));
if (!arg) return;
memcpy(arg, &m_selectedNodeId, sizeof(uint64_t));
gui_bridge_post_uasync_fn(chat_core_collect_conn_metrics_trampoline, arg);
}
void ConnMonitorWindow::onConnList(const uint8_t* data, int len) {
if (len < 2) return;
uint16_t count; memcpy(&count, data, 2);
const uint8_t* p = data + 2;
QHash<uint64_t, QListWidgetItem*> existing;
for (int i = 0; i < m_connList->count(); i++) {
auto* item = m_connList->item(i);
existing[(uint64_t)item->data(Qt::UserRole).toULongLong()] = item;
}
m_connList->blockSignals(true);
for (uint16_t i = 0; i < count && (p + CONN_LIST_ENTRY_SIZE) <= (data + len); i++) {
uint64_t nodeId; memcpy(&nodeId, p, 8); p += 8;
uint8_t flags = *p++;
uint8_t linkCount = *p++;
uint16_t rtt; memcpy(&rtt, p, 2); p += 2;
p += 2; /* inflightKb */
char name[33]; memcpy(name, p, 32); name[32] = '\0'; p += 32;
if (!nodeId) continue;
bool linksUp = (flags & 1) != 0;
bool initialized = (flags & 2) != 0;
QString color = linksUp ? "#2E7D32" : "#C62828";
QString status = linksUp ? "UP" : (initialized ? "init" : "DOWN");
QString nodeHex = QString("%1").arg(nodeId, 16, 16, QChar('0')).right(16).left(4);
QString rttStr = rtt > 0 ? QString::number(rtt / 10.0f, 'f', 1) : "-";
QString text = QString("[%1] %2 %3 rtt=%4ms")
.arg(nodeHex)
.arg(QString::fromUtf8(name).left(16), -16)
.arg(status + QString(" %1L").arg(linkCount), -10)
.arg(rttStr);
auto it = existing.find(nodeId);
if (it != existing.end()) {
auto* item = *it;
item->setText(text);
item->setForeground(QColor(color));
existing.erase(it);
} else {
auto* item = new QListWidgetItem(text, m_connList);
item->setData(Qt::UserRole, QVariant((qulonglong)nodeId));
item->setForeground(QColor(color));
}
}
for (auto it = existing.begin(); it != existing.end(); ++it)
delete *it;
m_connList->blockSignals(false);
if (!m_selectedNodeId && m_connList->count() > 0) {
m_connList->setCurrentRow(0);
onConnSelected(m_connList->item(0), nullptr);
}
}
void ConnMonitorWindow::onConnMetrics(const uint8_t* data, int len) {
if (len <= 0) return;
int scrollVal = m_details->verticalScrollBar()->value();
m_details->setPlainText(QString::fromUtf8((const char*)data, len));
m_details->verticalScrollBar()->setValue(scrollVal);
}
+34
View File
@@ -0,0 +1,34 @@
// connmonitorwindow.h — ETCP connection monitor (standalone, non-modal window)
#pragma once
#include <QDialog>
#include <QListWidget>
#include <QPlainTextEdit>
#include <QTimer>
#include <cstdint>
class ConnMonitorWindow : public QDialog {
Q_OBJECT
public:
explicit ConnMonitorWindow(QWidget* parent = nullptr);
~ConnMonitorWindow() override;
void onConnList(const uint8_t* data, int len);
void onConnMetrics(const uint8_t* data, int len);
protected:
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
private slots:
void onTimerTick();
void onConnSelected(QListWidgetItem* current, QListWidgetItem* previous);
private:
void requestMetricsForSelected();
QListWidget* m_connList;
QPlainTextEdit* m_details;
QTimer* m_timer;
uint64_t m_selectedNodeId = 0;
};
+3 -3
View File
@@ -40,10 +40,10 @@ static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) {
static struct ShutdownSentinel {
~ShutdownSentinel() {
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "main: static destructors done");
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "main: static destructors done");
#ifdef _WIN32
DWORD threads = count_threads();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "main: threads at exit=%lu", (unsigned long)threads);
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "main: threads at exit=%lu", (unsigned long)threads);
if (threads > 4) {
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "main: %lu hanging threads, TerminateProcess", (unsigned long)threads);
fflush(nullptr);
@@ -128,6 +128,6 @@ int main(int argc, char *argv[]) {
#endif
int ret = app.exec();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "main: app.exec() returned %d", ret);
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "main: app.exec() returned %d", ret);
return ret;
}
+21 -6
View File
@@ -8,6 +8,7 @@
#include "joindialog.h"
#include "settingsdialog.h"
#include "channelsettingsdialog.h"
#include "connmonitorwindow.h"
#include "creategroupdialog.h"
#include "invite_link.h"
#include "sound_manager.h"
@@ -249,7 +250,7 @@ void MainWindow::setupSoundFromConfig() {
audio_compressor_configure(m_recorder->compressor(), &compCfg);
}
}
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "AudioRecorder initialized (captureDevice=%d, opusPreset=%d, compressor=%d)",
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "AudioRecorder initialized (captureDevice=%d, opusPreset=%d, compressor=%d)",
m_recorder->captureDeviceIndex(), VoiceEncoder::preset(),
m_recorder->isCompressorEnabled() ? 1 : 0);
}
@@ -308,6 +309,7 @@ void MainWindow::setupConnects() {
connect(m_channelList, &ChannelList::joinRequested, this, &MainWindow::showJoinDialog);
connect(m_channelList, &ChannelList::createGroupRequested, this, &MainWindow::onCreateGroupRequested);
connect(m_channelList, &ChannelList::settingsRequested, this, &MainWindow::showSettings);
connect(m_channelList, &ChannelList::connMonitorRequested, this, &MainWindow::showConnMonitor);
connect(m_channelList, &ChannelList::channelSettingsRequested, this, &MainWindow::showChannelSettings);
connect(m_accountList, &AccountList::memberRenamed,
m_messageList, &MessageList::reloadLocalNicks);
@@ -428,6 +430,17 @@ void MainWindow::showSettings() {
reloadChannels();
}
void MainWindow::showConnMonitor() {
if (m_connMonitor) {
m_connMonitor->raise();
m_connMonitor->activateWindow();
return;
}
m_connMonitor = new ConnMonitorWindow(nullptr);
connect(m_connMonitor, &QDialog::destroyed, this, [this] { m_connMonitor = nullptr; });
m_connMonitor->show();
}
void MainWindow::onMessageReceived(const char* ch_id, int ch_id_len, uint64_t author) {
QString cid = QString::fromUtf8(ch_id, ch_id_len);
if (m_db && author != m_db->myNodeId())
@@ -598,14 +611,16 @@ void MainWindow::autoPlayTimerTick() {
QString fullPath = autoPlayMediaDir() + QStringLiteral("/") + item.channelId
+ QStringLiteral("/") + fp;
if (QFile::exists(fullPath)) {
QString chId = item.channelId;
qint64 msgId = item.msgId;
float dur = item.durationSec;
m_autoPlayQueue.dequeue();
m_autoPlayDownloading.remove(item.msgId);
m_autoPlayDownloading.remove(msgId);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "auto-play: playing ch=%s msg=%lld file=%s dur=%.1fs",
qPrintable(item.channelId), (long long)item.msgId, qPrintable(fullPath),
(double)item.durationSec);
qPrintable(chId), (long long)msgId, qPrintable(fullPath), (double)dur);
MessageDelegate::stopAllAutoPlay();
VoicePlayer::playOpusFile(fullPath);
MessageDelegate::startAutoPlay(fullPath, item.durationSec);
float actualDur = VoicePlayer::playOpusFile(fullPath);
MessageDelegate::startAutoPlay(fullPath, actualDur);
return;
}
}
+3
View File
@@ -13,6 +13,7 @@ class AccountList;
class DbManager;
class UtunNode;
class AudioRecorder;
class ConnMonitorWindow;
struct AutoPlayItem {
QString channelId;
@@ -41,6 +42,7 @@ private slots:
void showJoinDialog();
void onCreateGroupRequested();
void showSettings();
void showConnMonitor();
void showChannelSettings(const QString& channelId);
void autoPlayTimerTick();
@@ -79,6 +81,7 @@ private:
QString m_pendingChannelSelect;
QString m_currentChannelId;
AudioRecorder *m_recorder = nullptr;
ConnMonitorWindow *m_connMonitor = nullptr;
QQueue<AutoPlayItem> m_autoPlayQueue;
QTimer* m_autoPlayTimer = nullptr;
+1 -1
View File
@@ -284,7 +284,7 @@ MediaBlockInfo media_split_to_blocks(const QString& srcFile,
if (removeSrc) QFile::remove(srcFile);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "media_split_to_blocks: %s -> %d blocks (%lld bytes each) in %s",
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "media_split_to_blocks: %s -> %d blocks (%lld bytes each) in %s",
qPrintable(fi.fileName()), info.numBlocks, (long long)info.blockSize, qPrintable(mediaDir));
return info;
}
+10 -9
View File
@@ -153,14 +153,16 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
if (!st.playing && !st.paused) {
/* Start playback then seek */
float actualDur = VoicePlayer::playOpusFile(filePath);
if (actualDur <= 0.0f) return false;
targetSec = clickFrac * actualDur;
st.playing = true;
st.paused = false;
st.durationSec = dur;
st.durationSec = actualDur;
st.startMs = now - (qint64)(targetSec * 1000.0);
st.pausedPosSec = targetSec;
st.displayFrac = (targetSec > 0 && dur > 0) ? (targetSec / dur) : 0;
st.displayFrac = (targetSec > 0 && actualDur > 0) ? (targetSec / actualDur) : 0;
st.displayElapsed = targetSec;
VoicePlayer::playOpusFile(filePath);
int sr = SoundManager::instance()->currentPcmSampleRate();
if (sr > 0)
SoundManager::instance()->seekCurrentPcm((unsigned long long)(targetSec * sr));
@@ -222,15 +224,16 @@ bool MessageDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
SoundManager::instance()->stopCurrentPcm();
}
float actualDur = VoicePlayer::playOpusFile(filePath);
if (actualDur <= 0.0f) return false;
st.playing = true;
st.paused = false;
st.pausedPosSec = 0;
st.startMs = QDateTime::currentMSecsSinceEpoch();
st.durationSec = dur;
st.durationSec = actualDur;
st.displayFrac = 0;
st.displayElapsed = 0;
VoicePlayer::playOpusFile(filePath);
s_voiceTimer->start();
model->setData(index, 1, MsgVoicePlayStateRole);
return true;
@@ -850,8 +853,6 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
QColor idle(0x70, 0x70, 0x78, 130);
painter->setBrush((isPlaying || isPaused) ? (before ? played : unplayed) : idle);
painter->drawRect(QRect(x, y, bw, barH));
if (i == 0) GUI_DEBUG("voice paint: wfN=%d wfW=%d logV=%.2f barH=%d",
wfN, wfR.width(), logV, barH);
}
}
@@ -1187,12 +1188,12 @@ void MessageDelegate::drawAvatar(QPainter *p, const Layout &L,
p->restore();
}
void MessageDelegate::startAutoPlay(const QString& filePath, float durationSec) {
void MessageDelegate::startAutoPlay(const QString& filePath, float actualDurationSec) {
ensureVoiceTimer();
VoicePlayState& st = s_voiceStates[filePath];
st.playing = true;
st.paused = false;
st.durationSec = (durationSec > 0) ? durationSec : 1.0f;
st.durationSec = (actualDurationSec > 0) ? actualDurationSec : 1.0f;
st.startMs = QDateTime::currentMSecsSinceEpoch();
st.pausedPosSec = 0.0f;
st.displayFrac = 0.0f;
+1 -1
View File
@@ -48,7 +48,7 @@ public:
const QStyleOptionViewItem &option,
const QModelIndex &index) override;
static void startAutoPlay(const QString& filePath, float durationSec);
static void startAutoPlay(const QString& filePath, float actualDurationSec);
static void stopAllAutoPlay();
private:
+2 -4
View File
@@ -166,8 +166,6 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
wf.append((float)idx / 63.0f);
}
item->setData(wf, MsgVoiceWaveformRole);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "setVoiceMessageRoles: voice dur=%dms wf=%d exists=%d",
durMs, wf.size(), QFile::exists(fp));
}
}
if (ct == "application/octet-stream") {
@@ -659,9 +657,9 @@ void MessageList::updateReadPosition() {
void MessageList::cleanupAnimations() {
size_t n = s_icons.size();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "MessageList: cleanupAnimations clearing %zu icons", n);
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "MessageList: cleanupAnimations clearing %zu icons", n);
s_icons.clear();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "MessageList: cleanupAnimations done");
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "MessageList: cleanupAnimations done");
}
void MessageList::updateMessageProgress(const QString& chId, int64_t msgId,
+34 -6
View File
@@ -7,6 +7,7 @@
#include "soundsettingspage.h"
#include "audiodevicesettingspage.h"
#include "storagesettingspage.h"
#include "connmonitorwindow.h"
#include "../transport/gui_bridge.h"
#include "../../lib/mem.h"
#include "../db/db_manager.h"
@@ -31,7 +32,7 @@ SettingsDialog::SettingsDialog(const QString& configPath, DbManager* db, UtunNod
{
setWindowTitle("Settings");
setMinimumSize(760, 460);
setModal(true);
setWindowModality(Qt::WindowModal);
auto* mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(0);
@@ -48,6 +49,7 @@ SettingsDialog::SettingsDialog(const QString& configPath, DbManager* db, UtunNod
m_categoryList->addItem("Profile");
m_categoryList->addItem("Storage");
m_categoryList->addItem("Network");
m_categoryList->addItem("Connections");
m_categoryList->addItem("Database");
m_categoryList->addItem("Status");
m_categoryList->addItem("Nodes");
@@ -105,6 +107,22 @@ SettingsDialog::SettingsDialog(const QString& configPath, DbManager* db, UtunNod
m_networkPage = new NetworkSettingsPage(m_pages);
m_pages->addWidget(m_networkPage);
// Connections page — button to open standalone window
{
auto* connPage = new QWidget(m_pages);
auto* connLayout = new QVBoxLayout(connPage);
connLayout->setAlignment(Qt::AlignCenter);
auto* hintLabel = new QLabel("Live ETCP connection monitor\nwith per-link BBR statistics", connPage);
hintLabel->setAlignment(Qt::AlignCenter);
hintLabel->setStyleSheet("font-size: 12px; color: palette(text); padding: 20px;");
connLayout->addWidget(hintLabel);
auto* openBtn = new QPushButton("Open Connection Monitor", connPage);
openBtn->setStyleSheet("QPushButton { padding: 10px 20px; font-size: 13px; }");
connect(openBtn, &QPushButton::clicked, this, &SettingsDialog::onOpenConnMonitor);
connLayout->addWidget(openBtn);
m_pages->addWidget(connPage);
}
// Database page
m_databasePage = new DatabaseSettingsPage(db, m_pages);
m_pages->addWidget(m_databasePage);
@@ -187,11 +205,11 @@ void SettingsDialog::loadProfileFromConfig(const QString& path) {
void SettingsDialog::onCategoryChanged(int row) {
m_pages->setCurrentIndex(row);
if (row == 1) m_storagePage->loadFromDb();
if (row == 3) m_databasePage->refreshStatus();
if (row == 4) m_statusPage->refreshStatus();
if (row == 5) m_nodesPage->refreshNodes();
if (row == 6) m_soundPage->loadFromDb();
if (row == 7) m_audioDevicePage->loadFromDb();
if (row == 4) m_databasePage->refreshStatus();
if (row == 5) m_statusPage->refreshStatus();
if (row == 6) m_nodesPage->refreshNodes();
if (row == 7) m_soundPage->loadFromDb();
if (row == 8) m_audioDevicePage->loadFromDb();
}
void SettingsDialog::onSave() {
@@ -268,3 +286,13 @@ void SettingsDialog::onSave() {
}
accept();
}
void SettingsDialog::onOpenConnMonitor() {
if (m_connMonitorWindow) {
m_connMonitorWindow->raise();
m_connMonitorWindow->activateWindow();
return;
}
m_connMonitorWindow = new ConnMonitorWindow(nullptr);
m_connMonitorWindow->show();
}
+3
View File
@@ -13,6 +13,7 @@ class NetworkSettingsPage;
class DatabaseSettingsPage;
class StatusPage;
class NodesPage;
class ConnMonitorWindow;
class SoundSettingsPage;
class AudioDeviceSettingsPage;
class StorageSettingsPage;
@@ -29,6 +30,7 @@ public:
private slots:
void onCategoryChanged(int row);
void onSave();
void onOpenConnMonitor();
private:
void loadProfileFromConfig(const QString& path);
@@ -45,6 +47,7 @@ private:
DatabaseSettingsPage* m_databasePage;
StatusPage* m_statusPage;
NodesPage* m_nodesPage;
ConnMonitorWindow* m_connMonitorWindow = nullptr;
SoundSettingsPage* m_soundPage;
AudioDeviceSettingsPage* m_audioDevicePage;
StorageSettingsPage* m_storagePage;
+3 -3
View File
@@ -11,7 +11,7 @@ SoundManager* SoundManager::instance() {
}
SoundManager::~SoundManager() {
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: static destructor entered");
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "SoundManager: static destructor entered");
shutdown();
}
@@ -43,14 +43,14 @@ void SoundManager::shutdown() {
}
m_sounds.clear();
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: before ma_engine_uninit engine=%p", (void*)m_engine);
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "SoundManager: before ma_engine_uninit engine=%p", (void*)m_engine);
if (m_engine) { ma_engine_uninit(m_engine); delete m_engine; m_engine = nullptr; }
if (m_currentPcmSound) { delete m_currentPcmSound; m_currentPcmSound = nullptr; }
if (m_currentPcmBuffer) {
ma_audio_buffer* buf = (ma_audio_buffer*)m_currentPcmBuffer;
ma_audio_buffer_uninit(buf); delete buf; m_currentPcmBuffer = nullptr;
}
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SoundManager: after ma_engine_uninit");
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "SoundManager: after ma_engine_uninit");
m_initialized = false;
}
+6 -4
View File
@@ -75,7 +75,7 @@ int VoicePlayer::decodeOpusFile(const QString& filePath, std::vector<int16_t>& o
return frameCount;
}
void VoicePlayer::playOpusFile(const QString& filePath) {
float VoicePlayer::playOpusFile(const QString& filePath) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFile: %s", qPrintable(filePath));
std::vector<int16_t> pcm;
int sampleRate, channels;
@@ -83,26 +83,28 @@ void VoicePlayer::playOpusFile(const QString& filePath) {
if (decodeOpusFile(filePath, pcm, sampleRate, channels, duration) <= 0) {
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFile: decode failed for %s", qPrintable(filePath));
return;
return 0.0f;
}
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFile: decoded %zu samples %dHz %dch %.1fs",
pcm.size(), sampleRate, channels, duration);
SoundManager::instance()->playRawPcm(pcm.data(), pcm.size() / channels, sampleRate, channels);
return duration;
}
void VoicePlayer::playOpusFromReader(MediaBlockReader& reader) {
float VoicePlayer::playOpusFromReader(MediaBlockReader& reader) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFromReader: %s", qPrintable(reader.debugPath()));
std::vector<int16_t> pcm;
int sampleRate, channels;
float duration;
if (decodeOpusFromReader(reader, pcm, sampleRate, channels, duration) <= 0) {
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFromReader: decode failed");
return;
return 0.0f;
}
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "VoicePlayer::playOpusFromReader: decoded %zu samples %dHz %dch %.1fs",
pcm.size(), sampleRate, channels, duration);
SoundManager::instance()->playRawPcm(pcm.data(), pcm.size() / channels, sampleRate, channels);
return duration;
}
int VoicePlayer::decodeOpusFromReader(MediaBlockReader& reader, std::vector<int16_t>& outPcm,
+4 -4
View File
@@ -8,10 +8,10 @@ class MediaBlockReader;
class VoicePlayer {
public:
static void playOpusFile(const QString& filePath);
static float playOpusFile(const QString& filePath);
static int decodeOpusFile(const QString& filePath, std::vector<int16_t>& outPcm,
int& outSampleRate, int& outChannels, float& outDurationSec);
static void playOpusFromReader(MediaBlockReader& reader);
int& outSampleRate, int& outChannels, float& outDurationSec);
static float playOpusFromReader(MediaBlockReader& reader);
static int decodeOpusFromReader(MediaBlockReader& reader, std::vector<int16_t>& outPcm,
int& outSampleRate, int& outChannels, float& outDurationSec);
int& outSampleRate, int& outChannels, float& outDurationSec);
};