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;
|
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;
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user