From 2319053b2f658a8b22e706cfa37e98d7500693d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jul 2022 16:22:23 +0900 Subject: [PATCH 1/5] Expose async track `Start`/`Stop`/`Play` methods --- osu.Framework/Audio/Track/Track.cs | 15 +++++++++++ osu.Framework/Audio/Track/TrackBass.cs | 26 ++++++++++++------- osu.Framework/Audio/Track/TrackVirtual.cs | 18 +++++++++++++ osu.Framework/Graphics/Audio/DrawableTrack.cs | 7 +++++ 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index 9611ced1a2..33373b312a 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -82,12 +82,27 @@ public double Length /// Whether the seek was successful. public abstract bool Seek(double seek); + public abstract Task SeekAsync(double seek); + + public virtual Task StartAsync() + { + if (IsDisposed) + throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); + + return Task.CompletedTask; + } + public virtual void Start() { if (IsDisposed) throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); } + public virtual Task StopAsync() + { + return Task.CompletedTask; + } + public virtual void Stop() { } diff --git a/osu.Framework/Audio/Track/TrackBass.cs b/osu.Framework/Audio/Track/TrackBass.cs index 5f1d63231b..e628775f82 100644 --- a/osu.Framework/Audio/Track/TrackBass.cs +++ b/osu.Framework/Audio/Track/TrackBass.cs @@ -227,11 +227,14 @@ public override void Stop() StopAsync().WaitSafely(); } - public Task StopAsync() => EnqueueAction(() => + public override Task StopAsync() { - stopInternal(); - isRunning = isPlayed = false; - }); + return EnqueueAction(() => + { + stopInternal(); + isRunning = isPlayed = false; + }); + } private void stopInternal() { @@ -256,11 +259,16 @@ public override void Start() StartAsync().WaitSafely(); } - public Task StartAsync() => EnqueueAction(() => + public override async Task StartAsync() { - if (startInternal()) - isRunning = isPlayed = true; - }); + await base.StartAsync().ConfigureAwait(false); + + await EnqueueAction(() => + { + if (startInternal()) + isRunning = isPlayed = true; + }).ConfigureAwait(false); + } private bool startInternal() { @@ -291,7 +299,7 @@ public override bool Looping public override bool Seek(double seek) => SeekAsync(seek).GetResultSafely(); - public async Task SeekAsync(double seek) + public override async Task SeekAsync(double seek) { // At this point the track may not yet be loaded which is indicated by a 0 length. // In that case we still want to return true, hence the conservative length. diff --git a/osu.Framework/Audio/Track/TrackVirtual.cs b/osu.Framework/Audio/Track/TrackVirtual.cs index f042512e6c..a03b47bd6a 100644 --- a/osu.Framework/Audio/Track/TrackVirtual.cs +++ b/osu.Framework/Audio/Track/TrackVirtual.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Threading.Tasks; using osu.Framework.Timing; namespace osu.Framework.Audio.Track @@ -34,6 +35,23 @@ public override bool Seek(double seek) return seekOffset == seek; } + public override Task SeekAsync(double seek) + { + return Task.FromResult(Seek(seek)); + } + + public override Task StartAsync() + { + Start(); + return Task.CompletedTask; + } + + public override Task StopAsync() + { + Stop(); + return Task.CompletedTask; + } + public override void Start() { if (Length == 0) diff --git a/osu.Framework/Graphics/Audio/DrawableTrack.cs b/osu.Framework/Graphics/Audio/DrawableTrack.cs index aaaece9e17..8c884c7bfd 100644 --- a/osu.Framework/Graphics/Audio/DrawableTrack.cs +++ b/osu.Framework/Graphics/Audio/DrawableTrack.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Threading.Tasks; using osu.Framework.Audio; using osu.Framework.Audio.Mixing; using osu.Framework.Audio.Track; @@ -93,6 +94,12 @@ public void ResetSpeedAdjustments() RemoveAllAdjustments(AdjustableProperty.Tempo); } + public Task SeekAsync(double seek) => track.SeekAsync(seek); + + public Task StartAsync() => track.StartAsync(); + + public Task StopAsync() => track.StopAsync(); + public bool Seek(double seek) => track.Seek(seek); public void Start() => track.Start(); From 04dbeffc21c9be3affb7532644e86dbfeccb2b6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jul 2022 16:25:09 +0900 Subject: [PATCH 2/5] Also expose `RestartAsync` --- osu.Framework/Audio/Track/Track.cs | 13 ++++++++++--- osu.Framework/Graphics/Audio/DrawableTrack.cs | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index 33373b312a..ee5c01c642 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -13,8 +13,8 @@ public abstract class Track : AdjustableAudioComponent, ITrack, IAudioChannel public event Action? Completed; public event Action? Failed; - protected virtual void RaiseCompleted() => Completed?.Invoke(); - protected virtual void RaiseFailed() => Failed?.Invoke(); + protected void RaiseCompleted() => Completed?.Invoke(); + protected void RaiseFailed() => Failed?.Invoke(); public virtual bool IsDummyDevice => true; @@ -38,13 +38,20 @@ public virtual void Reset() /// /// Restarts this track from the while retaining adjustments. /// - public virtual void Restart() + public void Restart() { Stop(); Seek(RestartPoint); Start(); } + public async Task RestartAsync() + { + await StopAsync().ConfigureAwait(false); + await SeekAsync(RestartPoint).ConfigureAwait(false); + await StartAsync().ConfigureAwait(false); + } + public virtual void ResetSpeedAdjustments() { RemoveAllAdjustments(AdjustableProperty.Frequency); diff --git a/osu.Framework/Graphics/Audio/DrawableTrack.cs b/osu.Framework/Graphics/Audio/DrawableTrack.cs index 8c884c7bfd..b02eb0028e 100644 --- a/osu.Framework/Graphics/Audio/DrawableTrack.cs +++ b/osu.Framework/Graphics/Audio/DrawableTrack.cs @@ -94,6 +94,8 @@ public void ResetSpeedAdjustments() RemoveAllAdjustments(AdjustableProperty.Tempo); } + public Task RestartAsync() => track.RestartAsync(); + public Task SeekAsync(double seek) => track.SeekAsync(seek); public Task StartAsync() => track.StartAsync(); From 11edcb2e24b992b7cd580e9f44a9cf93a36cdaf8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jul 2022 21:42:35 +0900 Subject: [PATCH 3/5] Make all base methods `abstract` to avoid weird `base` calls --- osu.Framework/Audio/Track/Track.cs | 23 ++++------------------- osu.Framework/Audio/Track/TrackBass.cs | 23 +++++++---------------- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index ee5c01c642..d174e9ee97 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -91,28 +91,13 @@ public double Length public abstract Task SeekAsync(double seek); - public virtual Task StartAsync() - { - if (IsDisposed) - throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); + public abstract Task StartAsync(); - return Task.CompletedTask; - } + public abstract void Start(); - public virtual void Start() - { - if (IsDisposed) - throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); - } + public abstract Task StopAsync(); - public virtual Task StopAsync() - { - return Task.CompletedTask; - } - - public virtual void Stop() - { - } + public abstract void Stop(); public abstract bool IsRunning { get; } diff --git a/osu.Framework/Audio/Track/TrackBass.cs b/osu.Framework/Audio/Track/TrackBass.cs index e628775f82..6300889a33 100644 --- a/osu.Framework/Audio/Track/TrackBass.cs +++ b/osu.Framework/Audio/Track/TrackBass.cs @@ -220,12 +220,7 @@ protected override void UpdateState() public override bool IsDummyDevice => false; - public override void Stop() - { - base.Stop(); - - StopAsync().WaitSafely(); - } + public override void Stop() => StopAsync().WaitSafely(); public override Task StopAsync() { @@ -254,21 +249,17 @@ private void setDirection(bool reverse) public override void Start() { - base.Start(); + if (IsDisposed) + throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); StartAsync().WaitSafely(); } - public override async Task StartAsync() + public override Task StartAsync() => EnqueueAction(() => { - await base.StartAsync().ConfigureAwait(false); - - await EnqueueAction(() => - { - if (startInternal()) - isRunning = isPlayed = true; - }).ConfigureAwait(false); - } + if (startInternal()) + isRunning = isPlayed = true; + }); private bool startInternal() { From e2ad27db984b25204e29feaffee77ac84748126d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jul 2022 21:43:36 +0900 Subject: [PATCH 4/5] Rewrite `RestartAsync` to ensure all operations are performed as one transaction --- osu.Framework/Audio/Track/Track.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index d174e9ee97..2e665efab6 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -45,12 +45,12 @@ public void Restart() Start(); } - public async Task RestartAsync() + public Task RestartAsync() => EnqueueAction(() => { - await StopAsync().ConfigureAwait(false); - await SeekAsync(RestartPoint).ConfigureAwait(false); - await StartAsync().ConfigureAwait(false); - } + Stop(); + Seek(RestartPoint); + Start(); + }); public virtual void ResetSpeedAdjustments() { From 56aa671126cbfd1fd9c4c3a74136367b34918e90 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 7 Jul 2022 09:59:05 +0900 Subject: [PATCH 5/5] Use RestartAsync() in Restart() --- osu.Framework/Audio/Track/Track.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index 2e665efab6..304b305aff 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -5,6 +5,7 @@ using System; using System.Threading.Tasks; using osu.Framework.Audio.Mixing; +using osu.Framework.Extensions; namespace osu.Framework.Audio.Track { @@ -38,12 +39,7 @@ public virtual void Reset() /// /// Restarts this track from the while retaining adjustments. /// - public void Restart() - { - Stop(); - Seek(RestartPoint); - Start(); - } + public void Restart() => RestartAsync().WaitSafely(); public Task RestartAsync() => EnqueueAction(() => {