From e356fe9146bb4c62226e9c5108bfa9bf17171f68 Mon Sep 17 00:00:00 2001
From: fmarcac <188743521+fmarcac@users.noreply.github.com>
Date: Sat, 5 Sep 2026 14:20:26 +0200
Subject: Return the default ping for an empty SyncPlay group
---
Emby.Server.Implementations/SyncPlay/Group.cs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'Emby.Server.Implementations')
diff --git a/Emby.Server.Implementations/SyncPlay/Group.cs b/Emby.Server.Implementations/SyncPlay/Group.cs
index 38a0018a70..256faffbf4 100644
--- a/Emby.Server.Implementations/SyncPlay/Group.cs
+++ b/Emby.Server.Implementations/SyncPlay/Group.cs
@@ -451,7 +451,9 @@ namespace Emby.Server.Implementations.SyncPlay
max = Math.Max(max, session.Ping);
}
- return max;
+ // A group with no participants has no ping to report. Returning long.MinValue would
+ // overflow the callers that scale this value into ticks, so fall back to the default.
+ return max == long.MinValue ? DefaultPing : max;
}
///
--
cgit v1.2.3
From 7ce911a40145fce2600ba3ce042b82f7cb97d7f7 Mon Sep 17 00:00:00 2001
From: fmarcac <188743521+fmarcac@users.noreply.github.com>
Date: Sat, 5 Sep 2026 15:06:37 +0200
Subject: Clamp client reported ping in SyncPlay groups
---
Emby.Server.Implementations/SyncPlay/Group.cs | 14 +++++++++-
.../SyncPlay/WaitingGroupStateTests.cs | 32 ++++++++++++++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)
(limited to 'Emby.Server.Implementations')
diff --git a/Emby.Server.Implementations/SyncPlay/Group.cs b/Emby.Server.Implementations/SyncPlay/Group.cs
index 256faffbf4..923bfc67aa 100644
--- a/Emby.Server.Implementations/SyncPlay/Group.cs
+++ b/Emby.Server.Implementations/SyncPlay/Group.cs
@@ -90,6 +90,18 @@ namespace Emby.Server.Implementations.SyncPlay
/// The default ping.
public long DefaultPing { get; } = 500;
+ ///
+ /// Gets the maximum ping, in milliseconds, accepted from a session.
+ ///
+ ///
+ /// Pings are reported by clients and are scaled into the delays used to schedule playback,
+ /// so an unbounded value lets a single session push the whole group's resume point
+ /// arbitrarily far out, or overflow the arithmetic entirely. Anything above this is not a
+ /// usable measurement for synchronisation.
+ ///
+ /// The maximum ping.
+ public long MaxPing { get; } = 10000;
+
///
/// Gets the maximum time offset error accepted for dates reported by clients, in milliseconds.
///
@@ -438,7 +450,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
if (_participants.TryGetValue(session.Id, out GroupMember value))
{
- value.Ping = ping;
+ value.Ping = Math.Clamp(ping, 0, MaxPing);
}
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/SyncPlay/WaitingGroupStateTests.cs b/tests/Jellyfin.Server.Implementations.Tests/SyncPlay/WaitingGroupStateTests.cs
index 1e2467b3fc..0cccd5d4ca 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/SyncPlay/WaitingGroupStateTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/SyncPlay/WaitingGroupStateTests.cs
@@ -53,6 +53,34 @@ public class WaitingGroupStateTests
$"expected a resume delay of at least {group.DefaultPing} ms, got {scheduledDelay.TotalMilliseconds} ms");
}
+ [Theory]
+ [InlineData(4_000_000_000L)]
+ [InlineData(1_000_000_000_000_000L)]
+ [InlineData(long.MaxValue)]
+ [InlineData(-1L)]
+ public void UpdatePing_ClientReportsAnUnusablePing_IsClampedAndCannotStallTheGroup(long reportedPing)
+ {
+ var harness = new GroupHarness();
+ var group = harness.Group;
+
+ group.UpdatePing(harness.First, reportedPing);
+
+ Assert.InRange(group.GetHighestPing(), 0, group.MaxPing);
+
+ // The reported ping is scaled into the group's resume point, so an unclamped value either
+ // pushes playback months out or overflows the arithmetic outright.
+ var state = new PlayingGroupState(NullLoggerFactory.Instance);
+ var before = DateTime.UtcNow;
+ state.HandleRequest(
+ new UnpauseGroupRequest(),
+ group,
+ GroupStateType.Paused,
+ harness.First,
+ CancellationToken.None);
+
+ Assert.InRange(group.LastActivity - before, TimeSpan.Zero, TimeSpan.FromMinutes(1));
+ }
+
private sealed class GroupHarness
{
public GroupHarness()
@@ -73,6 +101,10 @@ public class WaitingGroupStateTests
.Setup(m => m.SendSyncPlayCommand(It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(Task.CompletedTask);
+ sessionManager
+ .Setup(m => m.SendSyncPlayGroupUpdate(It.IsAny(), It.IsAny>(), It.IsAny()))
+ .Returns(Task.CompletedTask);
+
Group = new SyncPlayGroup(
NullLoggerFactory.Instance,
userManager.Object,
--
cgit v1.2.3