Started to let all sfx related command be executed from the sfx manager
to avoid race condition and crashes.
This commit is contained in:
parent
4dc817890b
commit
216575a732
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user