diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 80954326b..455dca71c 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -1044,6 +1044,11 @@ Basic.Settings.Audio.EnablePushToTalk="Enable Push-to-talk" Basic.Settings.Audio.PushToTalkDelay="Push-to-talk delay" Basic.Settings.Audio.UnknownAudioDevice="[Device not connected or not available]" Basic.Settings.Audio.Disabled="Disabled" +Basic.Settings.Audio.LowLatencyBufferingMode="Low Latency Audio Buffering Mode (For Decklink/NDI outputs)" +Basic.Settings.Audio.LowLatencyBufferingWarning.Enabled="WARNING: Low latency audio buffering is enabled." +Basic.Settings.Audio.LowLatencyBufferingWarning="Low latency audio buffering mode may cause audio to glitch or stop playing from some sources." +Basic.Settings.Audio.LowLatencyBufferingWarning.Title="Enable low latency audio buffering mode?" +Basic.Settings.Audio.LowLatencyBufferingWarning.Confirm="Are you sure you want to enable low latency audio buffering mode?" # basic mode 'advanced' settings Basic.Settings.Advanced="Advanced" diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui index c7c480cd1..a2cd2f604 100644 --- a/UI/forms/OBSBasicSettings.ui +++ b/UI/forms/OBSBasicSettings.ui @@ -151,8 +151,8 @@ 0 0 - 806 - 1181 + 803 + 1226 @@ -1379,7 +1379,7 @@ 0 0 820 - 679 + 676 @@ -3972,7 +3972,7 @@ 0 0 820 - 641 + 632 @@ -4372,6 +4372,13 @@ + + + + Basic.Settings.Audio.LowLatencyBufferingMode + + + @@ -4904,8 +4911,8 @@ 0 0 - 609 - 870 + 713 + 923 @@ -5925,7 +5932,7 @@ peakMeterType monitoringDevice disableAudioDucking - baseResolution + lowLatencyBuffering outputResolution downscaleFilter fpsType @@ -5960,6 +5967,18 @@ enableLowLatencyMode browserHWAccel hotkeyFocusType + hideOBSFromCapture + closeProjectors + moreInfoButton + ignoreRecommended + useStreamKeyAdv + baseResolution + hotkeyFilterSearch + hotkeyFilterInput + hotkeyFilterReset + hotkeyScrollArea + sdrWhiteLevel + hdrNominalPeakLevel diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 712a1432f..f8155dc25 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -4409,7 +4409,7 @@ bool OBSBasic::ResetAudio() { ProfileScope("OBSBasic::ResetAudio"); - struct obs_audio_info ai; + struct obs_audio_info2 ai = {}; ai.samples_per_sec = config_get_uint(basicConfig, "Audio", "SampleRate"); @@ -4431,7 +4431,14 @@ bool OBSBasic::ResetAudio() else ai.speakers = SPEAKERS_STEREO; - return obs_reset_audio(&ai); + bool lowLatencyAudioBuffering = config_get_bool( + GetGlobalConfig(), "Audio", "LowLatencyAudioBuffering"); + if (lowLatencyAudioBuffering) { + ai.max_buffering_ms = 20; + ai.fixed_buffering = true; + } + + return obs_reset_audio2(&ai); } extern char *get_new_source_name(const char *name, const char *format); diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp index 5122bd06c..aedefa216 100644 --- a/UI/window-basic-settings.cpp +++ b/UI/window-basic-settings.cpp @@ -760,6 +760,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) SLOT(SurroundWarning(int))); connect(ui->channelSetup, SIGNAL(currentIndexChanged(int)), this, SLOT(SpeakerLayoutChanged(int))); + connect(ui->lowLatencyBuffering, SIGNAL(clicked(bool)), this, + SLOT(LowLatencyBufferingChanged(bool))); connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)), this, SLOT(SimpleRecordingQualityChanged())); connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)), this, @@ -926,6 +928,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) channelIndex = ui->channelSetup->currentIndex(); sampleRateIndex = ui->sampleRate->currentIndex(); + llBufferingEnabled = ui->lowLatencyBuffering->isChecked(); QRegularExpression rx("\\d{1,5}x\\d{1,5}"); QValidator *validator = new QRegularExpressionValidator(rx, this); @@ -934,6 +937,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) connect(ui->useStreamKeyAdv, SIGNAL(clicked()), this, SLOT(UseStreamKeyAdvClicked())); + + UpdateAudioWarnings(); } OBSBasicSettings::~OBSBasicSettings() @@ -2536,6 +2541,8 @@ void OBSBasicSettings::LoadAudioSettings() config_get_double(main->Config(), "Audio", "MeterDecayRate"); uint32_t peakMeterTypeIdx = config_get_uint(main->Config(), "Audio", "PeakMeterType"); + bool enableLLAudioBuffering = config_get_bool( + GetGlobalConfig(), "Audio", "LowLatencyAudioBuffering"); loading = true; @@ -2572,6 +2579,7 @@ void OBSBasicSettings::LoadAudioSettings() ui->meterDecayRate->setCurrentIndex(0); ui->peakMeterType->setCurrentIndex(peakMeterTypeIdx); + ui->lowLatencyBuffering->setChecked(enableLLAudioBuffering); LoadAudioDevices(); LoadAudioSources(); @@ -3754,6 +3762,14 @@ void OBSBasicSettings::SaveAudioSettings() main->UpdateVolumeControlsPeakMeterType(); } + if (WidgetChanged(ui->lowLatencyBuffering)) { + bool enableLLAudioBuffering = + ui->lowLatencyBuffering->isChecked(); + config_set_bool(GetGlobalConfig(), "Audio", + "LowLatencyAudioBuffering", + enableLLAudioBuffering); + } + for (auto &audioSource : audioSources) { auto source = OBSGetStrongRef(get<0>(audioSource)); if (!source) @@ -4287,9 +4303,12 @@ void OBSBasicSettings::AudioChangedRestart() if (!loading) { int currentChannelIndex = ui->channelSetup->currentIndex(); int currentSampleRateIndex = ui->sampleRate->currentIndex(); + bool currentLLAudioBufVal = + ui->lowLatencyBuffering->isChecked(); if (currentChannelIndex != channelIndex || - currentSampleRateIndex != sampleRateIndex) { + currentSampleRateIndex != sampleRateIndex || + currentLLAudioBufVal != llBufferingEnabled) { audioChanged = true; ui->audioMsg->setText( QTStr("Basic.Settings.ProgramRestart")); @@ -4318,13 +4337,9 @@ void OBSBasicSettings::SpeakerLayoutChanged(int idx) bool surround = IsSurround(speakerLayout.c_str()); if (surround) { - QString warning = QTStr(MULTI_CHANNEL_WARNING ".Enabled") + - QStringLiteral("\n\n") + - QTStr(MULTI_CHANNEL_WARNING); /* * Display all bitrates */ - ui->audioMsg_2->setText(warning); PopulateAACBitrates( {ui->simpleOutputABitrate, ui->advOutTrack1Bitrate, ui->advOutTrack2Bitrate, ui->advOutTrack3Bitrate, @@ -4335,7 +4350,6 @@ void OBSBasicSettings::SpeakerLayoutChanged(int idx) * Reset audio bitrate for simple and adv mode, update list of * bitrates and save setting. */ - ui->audioMsg_2->setText(QString()); RestrictResetBitrates( {ui->simpleOutputABitrate, ui->advOutTrack1Bitrate, ui->advOutTrack2Bitrate, ui->advOutTrack3Bitrate, @@ -4351,6 +4365,8 @@ void OBSBasicSettings::SpeakerLayoutChanged(int idx) SaveCombo(ui->advOutTrack5Bitrate, "AdvOut", "Track5Bitrate"); SaveCombo(ui->advOutTrack6Bitrate, "AdvOut", "Track6Bitrate"); } + + UpdateAudioWarnings(); } void OBSBasicSettings::HideOBSWindowWarning(int state) @@ -5257,6 +5273,56 @@ void OBSBasicSettings::SurroundWarning(int idx) lastChannelSetupIdx = idx; } +#define LL_BUFFERING_WARNING "Basic.Settings.Audio.LowLatencyBufferingWarning" + +void OBSBasicSettings::UpdateAudioWarnings() +{ + QString speakerLayoutQstr = ui->channelSetup->currentText(); + bool surround = IsSurround(QT_TO_UTF8(speakerLayoutQstr)); + bool lowBufferingActive = ui->lowLatencyBuffering->isChecked(); + + QString text; + + if (surround) { + text = QTStr(MULTI_CHANNEL_WARNING ".Enabled") + + QStringLiteral("\n\n") + QTStr(MULTI_CHANNEL_WARNING); + } + + if (lowBufferingActive) { + if (!text.isEmpty()) + text += QStringLiteral("\n\n"); + + text += QTStr(LL_BUFFERING_WARNING ".Enabled") + + QStringLiteral("\n\n") + QTStr(LL_BUFFERING_WARNING); + } + + ui->audioMsg_2->setText(text); +} + +void OBSBasicSettings::LowLatencyBufferingChanged(bool checked) +{ + if (checked) { + QString warningStr = QTStr(LL_BUFFERING_WARNING) + + QStringLiteral("\n\n") + + QTStr(LL_BUFFERING_WARNING ".Confirm"); + + auto button = OBSMessageBox::question( + this, QTStr(LL_BUFFERING_WARNING ".Title"), warningStr); + + if (button == QMessageBox::No) { + QMetaObject::invokeMethod(ui->lowLatencyBuffering, + "setChecked", + Qt::QueuedConnection, + Q_ARG(bool, false)); + return; + } + } + + QMetaObject::invokeMethod(this, "UpdateAudioWarnings", + Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "AudioChangedRestart"); +} + void OBSBasicSettings::SimpleRecordingQualityLosslessWarning(int idx) { if (idx == lastSimpleRecQualityIdx || idx == -1) diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp index b4bc43583..416942e0f 100644 --- a/UI/window-basic-settings.hpp +++ b/UI/window-basic-settings.hpp @@ -120,6 +120,7 @@ private: std::string savedTheme; int sampleRateIndex = 0; int channelIndex = 0; + bool llBufferingEnabled = false; int lastSimpleRecQualityIdx = 0; int lastServiceIdx = -1; @@ -379,6 +380,8 @@ private slots: void ReloadAudioSources(); void SurroundWarning(int idx); void SpeakerLayoutChanged(int idx); + void LowLatencyBufferingChanged(bool checked); + void UpdateAudioWarnings(); void OutputsChanged(); void Stream1Changed(); void VideoChanged();