From b78c8bc1de801fce15d9201a0f2f3100a51abe05 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Mon, 13 May 2024 19:25:48 +0200 Subject: [PATCH] Assume minimum volume when no volume update was received within 250ms Without this timeout the peak volume update, which was received last, would be used permanently until the next update arrives. This might only take place when the source produces audio output again. --- plugins/base/macro-condition-audio.cpp | 51 +++++++++++++++++++------- plugins/base/macro-condition-audio.hpp | 2 + 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/plugins/base/macro-condition-audio.cpp b/plugins/base/macro-condition-audio.cpp index 7c00aeea..d80c6a0b 100644 --- a/plugins/base/macro-condition-audio.cpp +++ b/plugins/base/macro-condition-audio.cpp @@ -61,26 +61,48 @@ MacroConditionAudio::~MacroConditionAudio() obs_volmeter_destroy(_volmeter); } +float MacroConditionAudio::GetVolumePeak() +{ + using namespace std::chrono_literals; + using namespace std::chrono; + static constexpr std::chrono::milliseconds timeout = 250ms; + + // OBS might rarely not update _peak quickly enough when very low + // intervals are configured on the General tab. + // In that case _peak might be set to negative infinity still, which + // will result in unexpected behavior, so we use the previously valid + // peak value instead. + // + // If no volume update was received within a timeout window, however, it + // is assumed, that the source no longer produces any audio output and + // thus a peak volume value of negative infinity is used. + + float peak; + + std::lock_guard lock(_peakMutex); + auto msPassedSinceLastUpdate = duration_cast( + high_resolution_clock::now() - _lastPeakUpdate); + if (_lastPeakUpdate.time_since_epoch().count() != 0 && + msPassedSinceLastUpdate > timeout) { + peak = -std::numeric_limits::infinity(); + } else { + peak = _peakUpdated ? _peak : _previousPeak; + } + + _previousPeak = peak; + _peak = -std::numeric_limits::infinity(); + _peakUpdated = false; + + return peak; +} + bool MacroConditionAudio::CheckOutputCondition() { bool ret = false; OBSSourceAutoRelease source = obs_weak_source_get_source(_audioSource.GetSource()); - // OBS might very rarely not update _peak quickly enough when very low - // intervals are configured on the General tab. - // In that case _peak might be set to negative infinity still, which - // will result in unexpected behavior, so we use the previously valid - // peak value instead. - float peak; - { - std::lock_guard lock(_peakMutex); - peak = _peakUpdated ? _peak : _previousPeak; - _previousPeak = peak; - _peak = -std::numeric_limits::infinity(); - _peakUpdated = false; - } - + float peak = GetVolumePeak(); double curVolume = _useDb ? peak : DecibelToPercent(peak) * 100; switch (_outputCondition) { @@ -349,6 +371,7 @@ void MacroConditionAudio::SetVolumeLevel(void *data, const float *, } } c->_peakUpdated = true; + c->_lastPeakUpdate = std::chrono::high_resolution_clock::now(); } void MacroConditionAudio::ResetVolmeter() diff --git a/plugins/base/macro-condition-audio.hpp b/plugins/base/macro-condition-audio.hpp index dbff654e..d165c78e 100644 --- a/plugins/base/macro-condition-audio.hpp +++ b/plugins/base/macro-condition-audio.hpp @@ -71,12 +71,14 @@ private: bool CheckMonitor(); bool CheckBalance(); void SetupTempVars(); + float GetVolumePeak(); Type _checkType = Type::OUTPUT_VOLUME; std::mutex _peakMutex; float _peak = -std::numeric_limits::infinity(); float _previousPeak = -std::numeric_limits::infinity(); bool _peakUpdated = false; + std::chrono::high_resolution_clock::time_point _lastPeakUpdate = {}; static bool _registered; static const std::string id; };