From 264a13705f7f8aa989180e4a19d59c7ececd6ae8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 28 Oct 2026 14:10:53 +0100 Subject: [PATCH] Finalize shared frame rate selection and deterministic call control verification --- tools/chatgui/src/stream_publish_window.cpp | 12 ++++-------- tools/chatgui/src/stream_publish_window.h | 1 - tools/chatgui/tests/test_call_commands.cpp | 6 +++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/tools/chatgui/src/stream_publish_window.cpp b/tools/chatgui/src/stream_publish_window.cpp index 432ac7c5..b10a5ed6 100644 --- a/tools/chatgui/src/stream_publish_window.cpp +++ b/tools/chatgui/src/stream_publish_window.cpp @@ -15,10 +15,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -189,7 +186,9 @@ StreamPublishWindow::StreamPublishWindow(StreamPublishEngine* engine, uint64_t g refreshModes(previous, previous.source.kind == StreamVideoSource::Screen); apply(); if (!m_engine->active()) synchronize(); }); - connect(m_resolution, &QMenu::triggered, this, [this] { refreshFrameRates(value(m_fps).toInt()); apply(); }); + connect(m_resolution, &QMenu::triggered, this, [this] { + populateFrameRates(m_fps, m_modes, value(m_resolution).toSize(), value(m_fps).toInt()); apply(); + }); for (auto* menu : {m_fps, m_codec, m_bitrate, m_maxQp, m_rotation, m_microphone}) connect(menu, &QMenu::triggered, this, &StreamPublishWindow::apply); for (auto* menu : {m_codec, m_maxQp}) connect(menu, &QMenu::triggered, this, [this] { if (!m_updating) synchronize(); }); @@ -368,7 +367,7 @@ void StreamPublishWindow::refreshModes(const StreamPublishConfig& previous, bool m_resolution->menuAction()->setToolTip(text("No supported video modes")); return; } const auto& mode = m_modes[selected]; - select(m_resolution, mode.size); refreshFrameRates(mode.fps); + select(m_resolution, mode.size); populateFrameRates(m_fps, m_modes, mode.size, mode.fps); if (!maximum && wanted != mode) DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "desktop video mode adjusted source=%s requested=%dx%d/%d selected=%dx%d/%d", qPrintable(source.name), wanted.size.width(), wanted.size.height(), wanted.fps, mode.size.width(), mode.size.height(), mode.fps); @@ -377,9 +376,6 @@ void StreamPublishWindow::refreshModes(const StreamPublishConfig& previous, bool source.kind == StreamVideoSource::Screen && mode.size == m_modes.front().size); } -void StreamPublishWindow::refreshFrameRates(int previous) { - populateFrameRates(m_fps, m_modes, value(m_resolution).toSize(), previous); -} void StreamPublishWindow::refreshCodecs() { QScopedValueRollback updating(m_updating, true); int previous = selected(m_codec) ? value(m_codec).toInt() : m_settings.value("codec").toInt(); diff --git a/tools/chatgui/src/stream_publish_window.h b/tools/chatgui/src/stream_publish_window.h index f5674aaa..c8d5afac 100644 --- a/tools/chatgui/src/stream_publish_window.h +++ b/tools/chatgui/src/stream_publish_window.h @@ -49,7 +49,6 @@ private: void refreshSources(); // Сохраняет выбранный handle; пропавший active-source не подменяется другим, до start возможен первый доступный. // Режимы camera/screen; выбирает близкий previous либо native screen. void refreshModes(const StreamPublishConfig& previous, bool maximum = false); - void refreshFrameRates(int previous); // Все стандартные и аппаратные FPS; недоступные для выбранного размера видимы и отключены. void updateMenuButtons(); // Обновляет иконки со значениями и подсказки верхнего ряда после выбора/синхронизации. void refreshCodecs(); // Перечитывает engine.codecs(), сохраняет текущий/saved codec, недоступный заменяет первым. void synchronize(); // Читает engine config/state без apply; настраивает controls и ограничения изменения audio/cursor/QP. diff --git a/tools/chatgui/tests/test_call_commands.cpp b/tools/chatgui/tests/test_call_commands.cpp index 44bf3788..72efc962 100644 --- a/tools/chatgui/tests/test_call_commands.cpp +++ b/tools/chatgui/tests/test_call_commands.cpp @@ -162,14 +162,13 @@ private slots: void videoSettingsMenus() { CallWindow window; window.setCallId(77); window.setPeerName(QStringLiteral("Video call")); window.setState(CallWindow::Active); auto* engine = window.findChild(); QVERIFY(engine); - auto* capture = engine->findChild(); QVERIFY(capture); - QObject::disconnect(capture, nullptr, engine, nullptr); // Детерминированные режимы, без открытия камеры/звонка. CallCameraDevice first{QStringLiteral("Main camera"), QByteArray("main"), {}}; stream_video_add_camera_modes(first.modes, QSize(1920, 1080), 29.97, 29.97); stream_video_add_camera_modes(first.modes, QSize(1280, 720), 15, 60); CallCameraDevice second{QStringLiteral("Secondary camera"), QByteArray("secondary"), {}}; stream_video_add_camera_modes(second.modes, QSize(640, 480), 7, 7); emit engine->camerasChanged({first, second}); + QSignalBlocker blocked(engine); // Аппаратные события не меняют тестовые режимы; камера/звонок не открываются. auto getMenu = [&window](const char* name) { return window.findChild(name); }; auto chosen = [](QMenu* menu) { auto* action = menu->findChild()->checkedAction(); return action ? action->data() : QVariant(); }; auto choose = [](QMenu* menu, const QVariant& value) { @@ -185,7 +184,8 @@ private slots: for (auto* action : fps->actions()) if (action->isCheckable()) QCOMPARE(action->isEnabled(), action->data().toInt() <= 30); choose(camera, second.id); QCOMPARE(chosen(resolution).toSize(), QSize(640, 480)); QCOMPARE(chosen(fps).toInt(), 7); - emit engine->camerasChanged({second, first}); QCOMPARE(chosen(camera).toByteArray(), second.id); QCOMPARE(chosen(fps).toInt(), 7); + blocked.unblock(); emit engine->camerasChanged({second, first}); blocked.reblock(); + QCOMPARE(chosen(camera).toByteArray(), second.id); QCOMPARE(chosen(fps).toInt(), 7); choose(camera, first.id); choose(resolution, QSize(1920, 1080)); choose(getMenu("callVideoCodec"), 1); auto* minimum = window.findChild("callVideoMinimumBitrate"); QVERIFY(minimum); auto* maximum = window.findChild("callVideoMaximumBitrate"); QVERIFY(maximum);