瀏覽代碼

CSoundHandler: fix memory leak and implement cache

This one fix issue 2091 and add caching that actually works.
ArseniyShestakov 10 年之前
父節點
當前提交
37a5930f84
共有 2 個文件被更改,包括 26 次插入64 次删除
  1. 23 60
      client/CMusicHandler.cpp
  2. 3 4
      client/CMusicHandler.h

+ 23 - 60
client/CMusicHandler.cpp

@@ -125,11 +125,10 @@ void CSoundHandler::release()
 	{
 		Mix_HaltChannel(-1);
 
-		std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
-		for (it=soundChunks.begin(); it != soundChunks.end(); it++)
+		for (auto &chunk : soundChunks)
 		{
-			if (it->second)
-				Mix_FreeChunk(it->second);
+			if (chunk.second)
+				Mix_FreeChunk(chunk.second);
 		}
 	}
 
@@ -137,44 +136,20 @@ void CSoundHandler::release()
 }
 
 // Allocate an SDL chunk and cache it.
-Mix_Chunk *CSoundHandler::GetSoundChunk(soundBase::soundID soundID)
+Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache)
 {
-	// Find its name
-	auto fname = sounds[soundID];
-	if (fname.empty())
-		return nullptr;
-
-	// Load and insert
 	try
 	{
-		auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + fname, EResType::SOUND))->readAll();
+		if (cache && soundChunks.find(sound) != soundChunks.end())
+			return soundChunks[sound];
 
+		auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
 		SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second);
-		Mix_Chunk *chunk;
-		chunk = Mix_LoadWAV_RW(ops, 1);	// will free ops
-		soundChunks.insert(std::pair<soundBase::soundID, Mix_Chunk *>(soundID, chunk));
-		return chunk;
-	}
-	catch(std::exception &e)
-	{
-        logGlobal->warnStream() << "Cannot get sound " << soundID << " chunk: " << e.what();
-		return nullptr;
-	}
-}
+		Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1);	// will free ops
 
-Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound)
-{
-	if (sound.empty())
-		return nullptr;
+		if (cache)
+			soundChunks.insert(std::pair<std::string, Mix_Chunk *>(sound, chunk));
 
-	// Load and insert
-	try
-	{
-		auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
-
-		SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second);
-		Mix_Chunk *chunk;
-		chunk = Mix_LoadWAV_RW(ops, 1);	// will free ops
 		return chunk;
 	}
 	catch(std::exception &e)
@@ -188,48 +163,36 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound)
 int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
 {
 	assert(soundID < soundBase::sound_after_last);
-	if (!initialized)
-		return -1;
+	auto sound = sounds[soundID];
+	logGlobal->traceStream() << "Attempt to play sound " << soundID << " with file name " << sound << " with cache";
 
-	int channel;
-	Mix_Chunk *chunk = GetSoundChunk(soundID);
-
-	if (chunk)
-	{
-		channel = Mix_PlayChannel(-1, chunk, repeats);
-		if (channel == -1)
-            logGlobal->errorStream() << "Unable to play sound file " << soundID << " , error " << Mix_GetError();
-		else
-			callbacks[channel];//insert empty callback
-	}
-	else
-	{
-		channel = -1;
-	}
-
-	return channel;
+	return playSound(sound, repeats, true);
 }
 
-int CSoundHandler::playSound(std::string sound, int repeats)
+int CSoundHandler::playSound(std::string sound, int repeats, bool cache)
 {
-	if (!initialized)
+	if (!initialized || sound.empty())
 		return -1;
 
 	int channel;
-	Mix_Chunk *chunk = GetSoundChunk(sound);
+	Mix_Chunk *chunk = GetSoundChunk(sound, cache);
 
 	if (chunk)
 	{
 		channel = Mix_PlayChannel(-1, chunk, repeats);
 		if (channel == -1)
+		{
             logGlobal->errorStream() << "Unable to play sound file " << sound << " , error " << Mix_GetError();
+			if (!cache)
+				Mix_FreeChunk(chunk);
+		}
+		else if (cache)
+			callbacks[channel];
 		else
-			callbacks[channel];//insert empty callback
+			callbacks[channel] = [chunk]{ Mix_FreeChunk(chunk);};
 	}
 	else
-	{
 		channel = -1;
-	}
 
 	return channel;
 }

+ 3 - 4
client/CMusicHandler.h

@@ -41,10 +41,9 @@ private:
 	SettingsListener listener;
 	void onVolumeChange(const JsonNode &volumeNode);
 
-	std::map<soundBase::soundID, Mix_Chunk *> soundChunks;
+	std::map<std::string, Mix_Chunk *> soundChunks;
 
-	Mix_Chunk *GetSoundChunk(soundBase::soundID soundID);
-	Mix_Chunk *GetSoundChunk(std::string &sound);
+	Mix_Chunk *GetSoundChunk(std::string &sound, bool cache);
 
 	//have entry for every currently active channel
 	//std::function will be nullptr if callback was not set
@@ -60,7 +59,7 @@ public:
 
 	// Sounds
 	int playSound(soundBase::soundID soundID, int repeats=0);
-	int playSound(std::string sound, int repeats=0);
+	int playSound(std::string sound, int repeats=0, bool cache=false);
 	int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
 	void stopSound(int handler);