Fix Sound memory leak (OutOfMemoryException), remove Music caching to free memory

This commit is contained in:
rob-v
2017-06-05 19:36:48 +02:00
committed by atlimit8
parent 2def72a078
commit 8276b17570
3 changed files with 70 additions and 8 deletions

View File

@@ -39,6 +39,8 @@ namespace OpenRA
readonly ISoundEngine soundEngine; readonly ISoundEngine soundEngine;
Cache<string, ISoundSource> sounds; Cache<string, ISoundSource> sounds;
ISoundSource rawSource; ISoundSource rawSource;
Func<string, ISoundSource> getSoundSource;
ISoundSource musicSource;
ISound music; ISound music;
ISound video; ISound video;
MusicInfo currentMusic; MusicInfo currentMusic;
@@ -81,9 +83,18 @@ namespace OpenRA
public void Initialize(ISoundLoader[] loaders, IReadOnlyFileSystem fileSystem) public void Initialize(ISoundLoader[] loaders, IReadOnlyFileSystem fileSystem)
{ {
sounds = new Cache<string, ISoundSource>(s => LoadSound(loaders, fileSystem, s)); StopMusic();
soundEngine.ReleaseSourcePool();
if (sounds != null)
foreach (var soundSource in sounds.Values)
soundSource.Dispose();
getSoundSource = s => LoadSound(loaders, fileSystem, s);
sounds = new Cache<string, ISoundSource>(getSoundSource);
currentSounds = new Dictionary<uint, ISound>(); currentSounds = new Dictionary<uint, ISound>();
music = null; music = null;
musicSource = null;
currentMusic = null; currentMusic = null;
video = null; video = null;
} }
@@ -195,11 +206,11 @@ namespace OpenRA
StopMusic(); StopMusic();
var sound = sounds[m.Filename]; musicSource = getSoundSource(m.Filename);
if (sound == null) if (musicSource == null)
return; return;
music = soundEngine.Play2D(sound, false, true, WPos.Zero, MusicVolume, false); music = soundEngine.Play2D(musicSource, false, true, WPos.Zero, MusicVolume, false);
currentMusic = m; currentMusic = m;
MusicPlaying = true; MusicPlaying = true;
} }
@@ -222,7 +233,13 @@ namespace OpenRA
public void StopMusic() public void StopMusic()
{ {
if (music != null) if (music != null)
{
soundEngine.StopSound(music); soundEngine.StopSound(music);
soundEngine.ReleaseSound(music);
music = null;
musicSource.Dispose();
musicSource = null;
}
MusicPlaying = false; MusicPlaying = false;
currentMusic = null; currentMusic = null;

View File

@@ -25,6 +25,8 @@ namespace OpenRA
void StopAllSounds(); void StopAllSounds();
void SetListenerPosition(WPos position); void SetListenerPosition(WPos position);
void SetSoundVolume(float volume, ISound music, ISound video); void SetSoundVolume(float volume, ISound music, ISound video);
void ReleaseSourcePool();
void ReleaseSound(ISound sound);
} }
public class SoundDevice public class SoundDevice
@@ -39,7 +41,7 @@ namespace OpenRA
} }
} }
public interface ISoundSource { } public interface ISoundSource : IDisposable { }
public interface ISound public interface ISound
{ {

View File

@@ -311,6 +311,26 @@ namespace OpenRA.Platforms.Default
AL10.alListenerf(EFX.AL_METERS_PER_UNIT, .01f); AL10.alListenerf(EFX.AL_METERS_PER_UNIT, .01f);
} }
public void ReleaseSourcePool()
{
foreach (var slot in sourcePool)
if (slot.Value.Sound != null)
ReleaseSound(slot.Key);
}
public void ReleaseSound(ISound sound)
{
var openAlSound = sound as OpenAlSound;
if (openAlSound != null)
ReleaseSound(openAlSound.Source);
}
void ReleaseSound(uint source)
{
AL10.alSourceStop(source);
AL10.alSourcei(source, AL10.AL_BUFFER, 0);
}
~OpenAlSoundEngine() ~OpenAlSoundEngine()
{ {
Dispose(false); Dispose(false);
@@ -341,7 +361,10 @@ namespace OpenRA.Platforms.Default
class OpenAlSoundSource : ISoundSource class OpenAlSoundSource : ISoundSource
{ {
public readonly uint Buffer; uint buffer;
bool disposed;
public uint Buffer { get { return buffer; } }
static int MakeALFormat(int channels, int bits) static int MakeALFormat(int channels, int bits)
{ {
@@ -353,8 +376,28 @@ namespace OpenRA.Platforms.Default
public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate)
{ {
AL10.alGenBuffers(new IntPtr(1), out Buffer); AL10.alGenBuffers(new IntPtr(1), out buffer);
AL10.alBufferData(Buffer, MakeALFormat(channels, sampleBits), data, new IntPtr(data.Length), new IntPtr(sampleRate)); AL10.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, new IntPtr(data.Length), new IntPtr(sampleRate));
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
AL10.alDeleteBuffers(new IntPtr(1), ref buffer);
disposed = true;
}
}
~OpenAlSoundSource()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} }
} }