Skip to content

Commit a79823b

Browse files
authored
Merge pull request #6608 from peppy/decoupled-clock-not-starting-source
Fix `DecouplingFramedClock` not starting source in edge case scenario
2 parents 9a3b685 + 1912761 commit a79823b

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

osu.Framework.Tests/Clocks/DecouplingFramedClockTest.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,36 @@ public void TestStartFromSource(bool allowDecoupling)
5757
Assert.That(decouplingClock.IsRunning, Is.True);
5858
}
5959

60+
[Test]
61+
public void TestSeekFromDecouplingWithoutProcessFrame()
62+
{
63+
decouplingClock.AllowDecoupling = true;
64+
65+
Assert.That(source.CurrentTime, Is.EqualTo(0));
66+
Assert.That(decouplingClock.CurrentTime, Is.EqualTo(0));
67+
68+
decouplingClock.Start();
69+
70+
decouplingClock.Seek(1000);
71+
decouplingClock.ProcessFrame();
72+
Assert.That(source.IsRunning, Is.True);
73+
74+
decouplingClock.Seek(-1000);
75+
// Intentionally no process frame.
76+
Assert.That(source.IsRunning, Is.False);
77+
78+
decouplingClock.Seek(-1);
79+
80+
// intentionally make sure that reference time has increased to push time into positive before a process frame.
81+
Thread.Sleep(500);
82+
decouplingClock.ProcessFrame();
83+
84+
while (decouplingClock.CurrentTime < 0)
85+
decouplingClock.ProcessFrame();
86+
87+
Assert.That(source.IsRunning, Is.True);
88+
}
89+
6090
[TestCase(true)]
6191
[TestCase(false)]
6292
public void TestSeekFromDecoupling(bool allowDecoupling)

osu.Framework/Timing/DecouplingFramedClock.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ public sealed class DecouplingFramedClock : ISourceChangeableClock, IAdjustableC
7575

7676
private IAdjustableClock adjustableSourceClock;
7777

78+
/// <summary>
79+
/// Denotes a state where a negative seek stopped the source clock and entered decoupled mode, meaning that
80+
/// after crossing into positive time again we should attempt to start and use the source clock.
81+
/// </summary>
82+
private bool pendingSourceRestartAfterNegativeSeek;
83+
7884
public DecouplingFramedClock(IClock? source = null)
7985
{
8086
ChangeSource(source);
@@ -118,12 +124,12 @@ public void ProcessFrame()
118124

119125
currentTime += elapsedReferenceTime;
120126

121-
// When crossing the zero time boundary forwards, we should start and use the source clock.
122-
// Note that this implicitly assumes the source starts at zero,
123-
// and additionally the right-side boundary is not handled as we don't know where the source's max time is.
124-
// This could be potentially handled if need be, if we had a notion of what the source's max allowable time is.
125-
if (lastTime < 0 && currentTime >= 0)
127+
// When crossing into positive time, we should attempt to start and use the source clock.
128+
// Note that this carries the common assumption that the source clock *should* be able to run from zero.
129+
if (pendingSourceRestartAfterNegativeSeek && currentTime >= 0)
126130
{
131+
pendingSourceRestartAfterNegativeSeek = false;
132+
127133
// We still need to check the seek was successful, else we might have already exceeded valid length of the source.
128134
lastSeekFailed = !adjustableSourceClock.Seek(currentTime);
129135
if (!lastSeekFailed)
@@ -166,6 +172,7 @@ public void ChangeSource(IClock? source)
166172
public void Reset()
167173
{
168174
adjustableSourceClock.Reset();
175+
pendingSourceRestartAfterNegativeSeek = false;
169176
shouldBeRunning = false;
170177
lastSeekFailed = false;
171178
currentTime = 0;
@@ -212,6 +219,7 @@ public bool Seek(double position)
212219

213220
// Ensure the underlying clock is stopped as we enter decoupled mode.
214221
adjustableSourceClock.Stop();
222+
pendingSourceRestartAfterNegativeSeek = position < 0;
215223
}
216224

217225
currentTime = position;

0 commit comments

Comments
 (0)