Clean up previous sample immediately on skin source change to avoid `Play` after disposal

This seems to be the simplest way to avoid calls to `Play` after the
underlying sample may have been disposed. As per the issue thread, a
local workaround is acceptable here.

Closes #13223.
This commit is contained in:
Dean Herbert 2021-06-08 15:05:14 +09:00
parent 6ebac0b462
commit f3f634e969
1 changed files with 39 additions and 5 deletions

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@ -70,22 +71,48 @@ public void Apply(ISampleInfo sampleInfo)
updateSample();
}
protected override void LoadComplete()
{
base.LoadComplete();
CurrentSkin.SourceChanged += skinChangedImmediate;
}
private void skinChangedImmediate()
{
// Clean up the previous sample immediately on a source change.
// This avoids a potential call to Play() of an already disposed sample (samples are disposed along with the skin, but SkinChanged is scheduled).
clearPreviousSamples();
}
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
updateSample();
}
/// <summary>
/// Whether this sample was playing before a skin source change.
/// </summary>
private bool wasPlaying;
private void clearPreviousSamples()
{
// only run if the samples aren't already cleared.
// this ensures the "wasPlaying" state is stored correctly even if multiple clear calls are executed.
if (!sampleContainer.Any()) return;
wasPlaying = Playing;
sampleContainer.Clear();
Sample = null;
}
private void updateSample()
{
if (sampleInfo == null)
return;
bool wasPlaying = Playing;
sampleContainer.Clear();
Sample = null;
var sample = CurrentSkin.GetSample(sampleInfo);
if (sample == null && AllowDefaultFallback)
@ -155,6 +182,13 @@ public bool Looping
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
CurrentSkin.SourceChanged -= skinChangedImmediate;
}
#region Re-expose AudioContainer
public BindableNumber<double> Volume => sampleContainer.Volume;