ppy / osu

rhythm is just a *click* away!
https://osu.ppy.sh
MIT License
15.18k stars 2.26k forks source link

Music controller stops playing after dragging the progress bar to the end #9398

Open TPGPL opened 4 years ago

TPGPL commented 4 years ago

Describe the bug: After you drag the progress bar in music controller to the end and then leave it in a different spot, the music won't play anymore and the progress bar won't bar. To resume playing the music, you have to pause and unpause the music.

Screenshots or videos showing encountered issue: https://www.youtube.com/watch?v=76dNIyzTX3g

osu!lazer version: 2020.629.0

Logs: database.log network.log performance.log runtime.log updater.log

EVAST9919 commented 4 years ago

Kinda the same thing happens with the replays. If you fast-forward the replay to the end and after that to the middle/start - the music will just stop playing and so is the time

bdach commented 4 years ago

@EVAST9919 That issue is tracked at #7295.

peppy commented 1 year ago

I was looking to fix this with the following change:

diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 0986c0513c..e8f1513e60 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -101,6 +101,11 @@ public void SeekTo(double position)
                     return;

                 CurrentTrack.Seek(position);
+
+                // The user may have seeked to the end of the track, then seeked back to a sane point.
+                // Let's make sure the track wasn't stopped from hitting the end.
+                if (!UserPauseRequested)
+                    Play();
             });
         }

But the track was still in an IsPlaying state which means the Play() operation does nothing due to the precondition:

JetBrains Rider 2023-09-22 at 07 50 35

It seems like part of this issue may lie in TrackBass's implementation:

JetBrains Rider 2023-09-22 at 07 48 43

It seems that when seeking to the end the endCallback isn't always run. Which means the track can get into a state where it is IsRunning but actually isn't.

peppy commented 1 year ago

This does work but feels like a hotfix for something we potentially want to fix framework-side? Maybe best to apply this for now? Interested in thoughts on this.

diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 0986c0513c..961fd2e797 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -101,6 +101,13 @@ public void SeekTo(double position)
                     return;

                 CurrentTrack.Seek(position);
+
+                // The user may have seeked to the end of the track, then seeked back to a sane point.
+                // Let's make sure the track wasn't stopped from hitting the end.
+                if (IsPlaying)
+                    // Using `Play()` here doesn't work due to a weirdness with TrackBass's implementation
+                    // See https://github.com/ppy/osu/issues/9398#issuecomment-1730967549
+                    CurrentTrack.StartAsync();
             });
         }
bdach commented 1 year ago

I dunno, the above seems pretty hideous to me. I wouldn't feel very good applying it, especially for an issue this minor.

peppy commented 1 year ago

Any idea what the correct behaviour here would be though? A TrackBass will stop when reaching the end of the track, so we will need a Play() call at very least. Do you agree with that (along with a framework side fix for the IsPlaying state)?

bdach commented 1 year ago

A TrackBass will stop when reaching the end of the track, so we will need a Play() call at very least.

Unfortunate that we have to work around this but this part sounds somewhat reasonable.

along with a framework side fix for the IsPlaying state

I'm more interested in what that fix would be, though. Earlier you said:

It seems that when seeking to the end the endCallback isn't always run.

which may well just be a BASS bug, but it's difficult to tell as their docs are ambiguous on when exactly a sync will be called. I guess we could put a SyncFlags.Seeking (BASS_SYNC_SETPOS) sync to try and catch these or something?