From 55e3b5ec5c24afda85f00649180990bb475ccb47 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Wed, 29 Nov 2023 18:57:19 +0100 Subject: [PATCH] FIX(server): Cap receiver ranges at a vol. diff of 5dB The factor difference cap works for larger volume adjustments, but for low volumes, the difference can easily exceed 5dB (from -24dB and lower, a difference of 0.05 in the factor is a difference of more than 5dB). (cherry picked from commit ea3e7cdce6da6b0f5544d0829871fefd23293938) --- src/murmur/AudioReceiverBuffer.h | 21 +++++++- .../TestAudioReceiverBuffer.cpp | 49 ++++++++++++++++--- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/murmur/AudioReceiverBuffer.h b/src/murmur/AudioReceiverBuffer.h index baef0ced37d..c7aeb14b1b7 100644 --- a/src/murmur/AudioReceiverBuffer.h +++ b/src/murmur/AudioReceiverBuffer.h @@ -62,6 +62,17 @@ class AudioReceiverBuffer { std::vector< AudioReceiver > &getReceivers(bool receivePositionalData); + /** + * If two receivers differ in their volume adjustment factors by this much or more, they will never end up in the + * same receiver range + */ + constexpr static const float maxFactorDiff = 0.05f; + /** + * If two receivers differ in their volume adjustment decibels by this much or more, they will never end up in the + * same receiver range + */ + constexpr static const int maxDecibelDiff = 5; + template< typename Iterator > static ReceiverRange< Iterator > getReceiverRange(Iterator begin, Iterator end) { ZoneScoped; @@ -82,8 +93,14 @@ class AudioReceiverBuffer { return lhs.getContext() == rhs.getContext() && Mumble::Protocol::protocolVersionsAreCompatible(lhs.getReceiver().m_version, rhs.getReceiver().m_version) - // Allow a little variance between volume adjustments - && std::abs(lhs.getVolumeAdjustment().factor - rhs.getVolumeAdjustment().factor) < 0.05f; + // The factor difference caps audible differences for high volume adjustments (where 1dB is already a + // big difference). Thus, this is a cap on the absolute loudness difference. + && std::abs(lhs.getVolumeAdjustment().factor - rhs.getVolumeAdjustment().factor) < maxFactorDiff + // The dB difference caps audible difference for low volume adjustments. E.g. a factor difference of + // 0.05 for an adjustment of -24dB is a difference of more than 5dB and therefore audible. Thus, this + // is a cap on the relative loudness difference. + && std::abs(lhs.getVolumeAdjustment().dbAdjustment - rhs.getVolumeAdjustment().dbAdjustment) + < maxDecibelDiff; }); return range; diff --git a/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp b/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp index 1b427256d07..fed889d07a5 100644 --- a/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp +++ b/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp @@ -39,14 +39,14 @@ Version::full_t vOld2 = Version::fromComponents(1, 3, 1); Version::full_t vOld3 = Version::fromComponents(1, 4, 0); Version::full_t vNew = Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION; -std::array< ServerUser, 5 > users = { ServerUser(0, vOld1), ServerUser(1, vOld2), ServerUser(2, vOld3), - ServerUser(3, vNew), ServerUser(4, vNew) }; +std::array< ServerUser, 6 > users = { ServerUser(0, vOld1), ServerUser(1, vOld2), ServerUser(2, vOld3), + ServerUser(3, vNew), ServerUser(4, vNew), ServerUser(5, vNew) }; -ServerUser deafUser(5, vOld1, true); -ServerUser selfDeafUser(6, vNew, false, true); -ServerUser contextUser1(7, vNew, false, false, "context1"); -ServerUser contextUser2(8, vNew, false, false, "context2"); -ServerUser contextUser3(9, vNew, false, false, "context1"); +ServerUser deafUser(6, vOld1, true); +ServerUser selfDeafUser(7, vNew, false, true); +ServerUser contextUser1(8, vNew, false, false, "context1"); +ServerUser contextUser2(9, vNew, false, false, "context2"); +ServerUser contextUser3(10, vNew, false, false, "context1"); struct Range { @@ -203,6 +203,41 @@ private slots: QCOMPARE(volumeReceiver->getVolumeAdjustment().factor, 1.4f); } + void test_getReceiverRange() { + AudioReceiverBuffer buffer; + + ServerUser &sender = contextUser2; + + buffer.addReceiver(sender, users[0], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromFactor(1.22)); + buffer.addReceiver(sender, users[1], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromFactor(1.22 + 0.6 * AudioReceiverBuffer::maxFactorDiff)); + buffer.addReceiver(sender, users[2], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromFactor(1.22 + 1.1 * AudioReceiverBuffer::maxFactorDiff)); + buffer.addReceiver(sender, users[3], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromDBAdjustment(-60)); + buffer.addReceiver(sender, users[4], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromDBAdjustment(-60 + AudioReceiverBuffer::maxDecibelDiff - 1)); + buffer.addReceiver(sender, users[5], Mumble::Protocol::AudioContext::NORMAL, false, + VolumeAdjustment::fromDBAdjustment(-60 + AudioReceiverBuffer::maxDecibelDiff)); + + buffer.preprocessBuffer(); + + std::vector< AudioReceiver > receivers = buffer.getReceivers(false); + auto receiverRange = AudioReceiverBuffer::getReceiverRange(receivers.begin(), receivers.end()); + + std::array< int, 4 > expectedGroupSizes = { 2, 1, 2, 1 }; + + for (std::size_t i = 0; i < expectedGroupSizes.size(); ++i) { + QVERIFY(receiverRange.begin != receiverRange.end); + QCOMPARE(std::distance(receiverRange.begin, receiverRange.end), expectedGroupSizes.at(i)); + receiverRange = AudioReceiverBuffer::getReceiverRange(receiverRange.end, receivers.end()); + } + + QVERIFY(receiverRange.begin == receiverRange.end); + } + + void test_encoding() { AudioReceiverBuffer buffer;