Keep microphone and no-audio options available during publication

This commit is contained in:
evgeny committed 2026-11-01 22:05:10 +01:00
1 parent 3eff460457
commit fabc76ef82
2 files changed
+38 -6

No files matched your search

+7 -4
View File
@@ -196,7 +196,9 @@ StreamPublishWindow::StreamPublishWindow(StreamPublishEngine* engine, uint64_t g
connect(menu, &QMenu::triggered, this, &StreamPublishWindow::apply);
connect(m_microphone, &QMenu::triggered, this, [this](QAction* action) {
if (m_updating || !action->isCheckable()) return;
if (action != m_noAudio) {
const bool audio = action != m_noAudio;
const bool audioChanged = m_engine->running() && audio != m_engine->config().audio;
if (audio) {
auto* sound = SoundManager::instance();
const QString id = action->data().toString();
if (id != sound->captureDevice()) {
@@ -204,6 +206,7 @@ StreamPublishWindow::StreamPublishWindow(StreamPublishEngine* engine, uint64_t g
emit microphoneChanged(id);
}
}
if (audioChanged) m_engine->setAudioEnabled(audio);
synchronize(); saveSettings();
});
for (auto* menu : {m_codec, m_maxQp}) connect(menu, &QMenu::triggered, this, [this] { if (!m_updating) synchronize(); });
@@ -398,7 +401,7 @@ void StreamPublishWindow::refreshMicrophones() {
const QString input = SoundManager::instance()->captureDevice();
clearOptions(m_microphone, "Audio source");
m_noAudio = addOption(m_microphone, text("No audio"), QVariant());
m_noAudio->setEnabled(!m_engine->active());
m_noAudio->setEnabled(!m_engine->active() || m_engine->running());
addOption(m_microphone, text("Default microphone"), QString());
for (const auto& device : SoundManager::enumerateCaptureDevices()) addOption(m_microphone, device.name, device.id);
if (!option(m_microphone, input)) addOption(m_microphone, text("Selected microphone unavailable"), input);
@@ -448,8 +451,8 @@ void StreamPublishWindow::synchronize() {
&& selected(m_source) && selected(m_resolution) && selected(m_fps) && selected(m_codec)));
for (auto* menu : {m_source, m_resolution, m_fps, m_codec, m_bitrate, m_rotation})
menu->menuAction()->setEnabled(!active || m_engine->running());
m_microphone->menuAction()->setEnabled(!active || (m_engine->running() && m_engine->config().audio));
m_noAudio->setEnabled(!active);
m_microphone->menuAction()->setEnabled(!active || m_engine->running());
m_noAudio->setEnabled(!active || m_engine->running());
if (active) m_audioMuted = m_engine->muted();
bool audio = active ? m_engine->config().audio : selection().audio;
m_sound->setEnabled(audio && (!active || m_engine->running()));
+31 -2
View File
@@ -1194,7 +1194,7 @@ private slots:
QTRY_VERIFY(stream_member_load(inst, group, inst->node_id, &before, nullptr) == STREAM_OK && before.published);
StreamPublishWindow controls(&engine, group);
auto* audio = menu(controls, "streamAudioSource"); QVERIFY(audio->menuAction()->isEnabled());
QVERIFY(!choices(audio).front()->isEnabled());
QVERIFY(choices(audio).front()->isEnabled());
const unsigned opened = captureOpens.load(), encoded = audioEncodes.load();
slowCaptureClose = true;
auto restoreClose = qScopeGuard([] { slowCaptureClose = false; });
@@ -1244,12 +1244,35 @@ private slots:
QVERIFY(gui_stream_open(210, group, inst->node_id, member.source.source_epoch));
auto closeViewer = qScopeGuard([] { gui_stream_stop(210); });
StreamRecord out; QVERIFY(record(210, StreamRecordKind::Opened, out)); QVERIFY(record(210, StreamRecordKind::Video, out));
QCOMPARE(out.format.audio_codec, uint8_t(0)); QCOMPARE(audioEncodes.load(), 0u);
QCOMPARE(out.format.audio_codec, uint8_t(STREAM_MEDIA_OPUS_STEREO)); QCOMPARE(audioEncodes.load(), 0u);
QVERIFY(!member.audio_enabled);
if (scenario == 2) QCOMPARE(captureOpens.load(), 0u);
AudioCaptureLease microphone; QVERIFY(microphone.acquire()); microphone.release();
QVERIFY(engine.running()); QVERIFY(errors.isEmpty());
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "fixture video without microphone scenario=%d audio_codec=%u capture_opens=%u",
scenario, out.format.audio_codec, captureOpens.load());
StreamPublishWindow controls(&engine, group);
auto* audio = menu(controls, "streamAudioSource");
QVERIFY(audio->menuAction()->isEnabled()); QVERIFY(choices(audio).front()->isEnabled());
failCaptureOpen = false;
choose(audio, QString()); // Включается и при неизменившемся общем ID микрофона.
QVERIFY(engine.config().audio); QTRY_VERIFY(audioEncodes.load() > 0);
stream_member_state enabled{};
QTRY_VERIFY(stream_member_load(inst, group, inst->node_id, &enabled, nullptr) == STREAM_OK && enabled.audio_enabled);
QCOMPARE(enabled.source.source_epoch, member.source.source_epoch);
QVERIFY(record(210, StreamRecordKind::Audio, out));
const auto audioPts = out.pts;
choose(audio, QVariant());
QVERIFY(!engine.config().audio); QVERIFY(engine.running()); QVERIFY(audio->menuAction()->isEnabled());
stream_member_state disabled{};
QTRY_VERIFY(stream_member_load(inst, group, inst->node_id, &disabled, nullptr) == STREAM_OK && !disabled.audio_enabled);
QCOMPARE(disabled.source.source_epoch, member.source.source_epoch);
choose(audio, QString());
QVERIFY(engine.config().audio);
do { QVERIFY(record(210, StreamRecordKind::Audio, out)); } while (out.pts <= audioPts);
QVERIFY(engine.running()); QVERIFY(errors.isEmpty());
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "fixture live audio selection scenario=%d toggles=3 epoch=%llx audio_PTS=%llu->%llu",
scenario, (unsigned long long)member.source.source_epoch, (unsigned long long)audioPts, (unsigned long long)out.pts);
engine.stop(); QTRY_VERIFY_WITH_TIMEOUT(!engine.active(), 4000);
#else
QSKIP("Capture and null audio instrumentation unavailable");
@@ -1314,6 +1337,12 @@ private slots:
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "fixture microphone timeout initial=%d detected_ms=%lld video_PTS=%llu->%llu epoch=%llx audio_enabled=0",
initialFailure, (long long)timeoutMs, (unsigned long long)firstPts, (unsigned long long)out.pts,
(unsigned long long)after.source.source_epoch);
suppressMicrophone = false;
choose(menu(controls, "streamAudioSource"), QString());
QVERIFY(engine.config().audio);
QTRY_VERIFY(stream_member_load(inst, group, inst->node_id, &after, nullptr) == STREAM_OK && after.audio_enabled);
QCOMPARE(after.source.source_epoch, before.source.source_epoch);
QVERIFY(record(211, StreamRecordKind::Audio, out)); QVERIFY(engine.running()); QVERIFY(errors.isEmpty());
engine.stop(); QTRY_VERIFY_WITH_TIMEOUT(!engine.active(), 4000);
#else
QSKIP("Capture and encoder instrumentation unavailable");