Fix Sound memory leak (OutOfMemoryException), remove Music caching to free memory
This commit is contained in:
@@ -39,6 +39,8 @@ namespace OpenRA
|
||||
readonly ISoundEngine soundEngine;
|
||||
Cache<string, ISoundSource> sounds;
|
||||
ISoundSource rawSource;
|
||||
Func<string, ISoundSource> getSoundSource;
|
||||
ISoundSource musicSource;
|
||||
ISound music;
|
||||
ISound video;
|
||||
MusicInfo currentMusic;
|
||||
@@ -81,9 +83,18 @@ namespace OpenRA
|
||||
|
||||
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>();
|
||||
music = null;
|
||||
musicSource = null;
|
||||
currentMusic = null;
|
||||
video = null;
|
||||
}
|
||||
@@ -195,11 +206,11 @@ namespace OpenRA
|
||||
|
||||
StopMusic();
|
||||
|
||||
var sound = sounds[m.Filename];
|
||||
if (sound == null)
|
||||
musicSource = getSoundSource(m.Filename);
|
||||
if (musicSource == null)
|
||||
return;
|
||||
|
||||
music = soundEngine.Play2D(sound, false, true, WPos.Zero, MusicVolume, false);
|
||||
music = soundEngine.Play2D(musicSource, false, true, WPos.Zero, MusicVolume, false);
|
||||
currentMusic = m;
|
||||
MusicPlaying = true;
|
||||
}
|
||||
@@ -222,7 +233,13 @@ namespace OpenRA
|
||||
public void StopMusic()
|
||||
{
|
||||
if (music != null)
|
||||
{
|
||||
soundEngine.StopSound(music);
|
||||
soundEngine.ReleaseSound(music);
|
||||
music = null;
|
||||
musicSource.Dispose();
|
||||
musicSource = null;
|
||||
}
|
||||
|
||||
MusicPlaying = false;
|
||||
currentMusic = null;
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace OpenRA
|
||||
void StopAllSounds();
|
||||
void SetListenerPosition(WPos position);
|
||||
void SetSoundVolume(float volume, ISound music, ISound video);
|
||||
void ReleaseSourcePool();
|
||||
void ReleaseSound(ISound sound);
|
||||
}
|
||||
|
||||
public class SoundDevice
|
||||
@@ -39,7 +41,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISoundSource { }
|
||||
public interface ISoundSource : IDisposable { }
|
||||
|
||||
public interface ISound
|
||||
{
|
||||
|
||||
@@ -311,6 +311,26 @@ namespace OpenRA.Platforms.Default
|
||||
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()
|
||||
{
|
||||
Dispose(false);
|
||||
@@ -341,7 +361,10 @@ namespace OpenRA.Platforms.Default
|
||||
|
||||
class OpenAlSoundSource : ISoundSource
|
||||
{
|
||||
public readonly uint Buffer;
|
||||
uint buffer;
|
||||
bool disposed;
|
||||
|
||||
public uint Buffer { get { return buffer; } }
|
||||
|
||||
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)
|
||||
{
|
||||
AL10.alGenBuffers(new IntPtr(1), out Buffer);
|
||||
AL10.alBufferData(Buffer, MakeALFormat(channels, sampleBits), data, new IntPtr(data.Length), new IntPtr(sampleRate));
|
||||
AL10.alGenBuffers(new IntPtr(1), out buffer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user