Started to let all sfx related command be executed from the sfx manager

to avoid race condition and crashes.
This commit is contained in:
hiker 2014-10-11 11:55:02 +11:00
parent 4dc817890b
commit 216575a732
3 changed files with 66 additions and 23 deletions

View File

@ -106,9 +106,9 @@ SFXManager::SFXManager()
if (!sfxAllowed()) return;
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_to_play.lock();
m_sfx_to_play.getData().clear();
m_sfx_to_play.unlock();
m_sfx_commands.lock();
m_sfx_commands.getData().clear();
m_sfx_commands.unlock();
} // SoundManager
@ -163,15 +163,17 @@ SFXManager::~SFXManager()
* separate thread.
* \param sfx The sound effect to be started.
*/
void SFXManager::queue(SFXBase *sfx)
void SFXManager::queue(SFXCommands command, SFXBase *sfx)
{
// Don't add sfx that are either not working correctly (e.g. because sfx
// are disabled);
if(sfx && sfx->getStatus()==SFX_UNKNOWN ) return;
m_sfx_to_play.lock();
m_sfx_to_play.getData().push_back(sfx);
m_sfx_to_play.unlock();
SFXCommand *sfx_command = new SFXCommand(command, sfx);
m_sfx_commands.lock();
m_sfx_commands.getData().push_back(sfx_command);
m_sfx_commands.unlock();
// Wake up the sfx thread
pthread_cond_signal(&m_cond_request);
@ -183,7 +185,7 @@ void SFXManager::queue(SFXBase *sfx)
*/
void SFXManager::stopThread()
{
queue(NULL);
queue(SFX_EXIT, NULL);
} // stopThread
//----------------------------------------------------------------------------
@ -198,35 +200,47 @@ void* SFXManager::mainLoop(void *obj)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
me->m_sfx_to_play.lock();
me->m_sfx_commands.lock();
// Wait till we have an empty sfx in the queue
while (me->m_sfx_to_play.getData().empty() ||
me->m_sfx_to_play.getData().front()!=NULL )
while (me->m_sfx_commands.getData().empty() ||
me->m_sfx_commands.getData().front()->m_command!=SFX_EXIT)
{
bool empty = me->m_sfx_to_play.getData().empty();
bool empty = me->m_sfx_commands.getData().empty();
// Wait in cond_wait for a request to arrive. The 'while' is necessary
// since "spurious wakeups from the pthread_cond_wait ... may occur"
// (pthread_cond_wait man page)!
while (empty)
{
pthread_cond_wait(&me->m_cond_request, me->m_sfx_to_play.getMutex());
empty = me->m_sfx_to_play.getData().empty();
pthread_cond_wait(&me->m_cond_request, me->m_sfx_commands.getMutex());
empty = me->m_sfx_commands.getData().empty();
}
SFXBase *current = me->m_sfx_to_play.getData().front();
me->m_sfx_to_play.getData().erase(me->m_sfx_to_play.getData().begin());
SFXCommand *current = me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
if (!current) // empty sfx indicates to abort the sfx manager
if (current->m_command == SFX_EXIT)
break;
me->m_sfx_to_play.unlock();
current->reallyPlayNow();
me->m_sfx_to_play.lock();
me->m_sfx_commands.unlock();
switch(current->m_command)
{
case SFX_PLAY: current->m_sfx->reallyPlayNow(); break;
default: assert("Not yet supported.");
}
delete current;
current = NULL;
me->m_sfx_commands.lock();
} // while
// Clean up memory to avoid leak detection
while(!me->m_sfx_commands.getData().empty())
{
delete me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
}
return NULL;
} // mainLoop

View File

@ -19,6 +19,7 @@
#ifndef HEADER_SFX_MANAGER_HPP
#define HEADER_SFX_MANAGER_HPP
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/synchronised.hpp"
#include "utils/vec3.hpp"
@ -57,6 +58,18 @@ private:
public:
/** The various commands to be executed by the sfx manager thread
* for each sfx. */
enum SFXCommands
{
SFX_PLAY = 1,
SFX_STOP = 2,
SFX_PAUSE = 3,
SFX_RESUME = 4,
SFX_DELETE = 5,
SFX_EXIT = 6,
}; // SFXCommands
/**
* Entries for custom SFX sounds. These are unique for each kart.
* eg. kart->playCustomSFX(SFX_MANAGER::CUSTOM_HORN)
@ -85,6 +98,22 @@ public:
private:
/** Data structure for the queue, which stores a sfx and the command to
* execute for it. */
class SFXCommand : public NoCopy
{
private:
LEAK_CHECK()
public:
SFXBase *m_sfx;
SFXCommands m_command;
SFXCommand(SFXCommands command, SFXBase *base)
{
m_command = command;
m_sfx = base;
}
}; // SFXCommand
/** Listener position */
Vec3 m_position;
@ -96,7 +125,7 @@ private:
std::vector<SFXBase*> m_all_sfx;
/** The list of sound effects to be played in the next update. */
Synchronised< std::vector<SFXBase*> > m_sfx_to_play;
Synchronised< std::vector<SFXCommand*> > m_sfx_commands;
/** To play non-positional sounds without having to create a new object for each */
std::map<std::string, SFXBase*> m_quick_sounds;
@ -124,7 +153,7 @@ private:
public:
static void create();
static void destroy();
void queue(SFXBase *sfx);
void queue(SFXCommands command, SFXBase *sfx);
// ------------------------------------------------------------------------
/** Static function to get the singleton sfx manager. */
static SFXManager *get()

View File

@ -234,7 +234,7 @@ void SFXOpenAL::play()
// but for STK this is correct since we don't want to start the same
// sfx twice.
m_is_playing = true;
SFXManager::get()->queue(this);
SFXManager::get()->queue(SFXManager::SFX_PLAY, this);
} // play
//-----------------------------------------------------------------------------