Run SFX in a separate thread (for #1511).
This commit is contained in:
parent
2b86705dc0
commit
99fd49bdc0
@ -24,6 +24,7 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
@ -68,6 +69,7 @@ void SFXManager::destroy()
|
||||
*/
|
||||
SFXManager::SFXManager()
|
||||
{
|
||||
|
||||
// The sound manager initialises OpenAL
|
||||
m_initialized = music_manager->initialized();
|
||||
m_master_gain = UserConfigParams::m_sfx_volume;
|
||||
@ -75,11 +77,39 @@ SFXManager::SFXManager()
|
||||
m_position = Vec3(0,0,0);
|
||||
|
||||
loadSfx();
|
||||
|
||||
pthread_cond_init(&m_cond_request, NULL);
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
// Should be the default, but just in case:
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
|
||||
m_thread_id.setAtomic(new pthread_t());
|
||||
// The thread is created even if there atm sfx are disabled
|
||||
// (since the user might enable it later).
|
||||
int error = pthread_create(m_thread_id.getData(), &attr,
|
||||
&SFXManager::mainLoop, this);
|
||||
if (error)
|
||||
{
|
||||
m_thread_id.lock();
|
||||
delete m_thread_id.getData();
|
||||
m_thread_id.unlock();
|
||||
m_thread_id.setAtomic(0);
|
||||
Log::error("HTTP Manager", "Could not create thread, error=%d.",
|
||||
errno);
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
if (!sfxAllowed()) return;
|
||||
|
||||
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
|
||||
m_sfx_to_play.lock();
|
||||
m_sfx_to_play.getData().clear();
|
||||
m_sfx_to_play.unlock();
|
||||
|
||||
} // SoundManager
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -87,6 +117,12 @@ SFXManager::SFXManager()
|
||||
*/
|
||||
SFXManager::~SFXManager()
|
||||
{
|
||||
m_thread_id.lock();
|
||||
pthread_join(*m_thread_id.getData(), NULL);
|
||||
delete m_thread_id.getData();
|
||||
m_thread_id.unlock();
|
||||
pthread_cond_destroy(&m_cond_request);
|
||||
|
||||
// ---- clear m_all_sfx
|
||||
const int sfx_amount = m_all_sfx.size();
|
||||
for (int n=0; n<sfx_amount; n++)
|
||||
@ -131,29 +167,68 @@ void SFXManager::queue(SFXBase *sfx)
|
||||
{
|
||||
// Don't add sfx that are either not working correctly (e.g. because sfx
|
||||
// are disabled);
|
||||
if(sfx->getStatus()==SFX_UNKNOWN ) return;
|
||||
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();
|
||||
} // playSFX
|
||||
// Wake up the sfx thread
|
||||
pthread_cond_signal(&m_cond_request);
|
||||
|
||||
} // queue
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/** Starts all sfx that are queues to be started. Called once per frame.
|
||||
/** Puts a NULL request into the queue, which will trigger the thread to
|
||||
* exit.
|
||||
*/
|
||||
void SFXManager::update()
|
||||
void SFXManager::stopThread()
|
||||
{
|
||||
m_sfx_to_play.lock();
|
||||
while(!m_sfx_to_play.getData().empty())
|
||||
queue(NULL);
|
||||
} // stopThread
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/** This loops runs in a different threads, and starts sfx to be played.
|
||||
* This can sometimes take up to 5 ms, so it needs to be handled in a thread
|
||||
* in order to avoid rendering delays.
|
||||
* \param obj A pointer to the SFX singleton.
|
||||
*/
|
||||
void* SFXManager::mainLoop(void *obj)
|
||||
{
|
||||
SFXManager *me = (SFXManager*)obj;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
|
||||
me->m_sfx_to_play.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 )
|
||||
{
|
||||
SFXBase *sfx = m_sfx_to_play.getData().front();
|
||||
m_sfx_to_play.getData().erase(m_sfx_to_play.getData().begin());
|
||||
m_sfx_to_play.unlock();
|
||||
sfx->reallyPlayNow();
|
||||
m_sfx_to_play.lock();
|
||||
} // while !empty
|
||||
m_sfx_to_play.unlock();
|
||||
} // update
|
||||
bool empty = me->m_sfx_to_play.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();
|
||||
}
|
||||
|
||||
SFXBase *current = me->m_sfx_to_play.getData().front();
|
||||
me->m_sfx_to_play.getData().erase(me->m_sfx_to_play.getData().begin());
|
||||
|
||||
if (!current) // empty sfx indicates to abort the sfx manager
|
||||
break;
|
||||
|
||||
me->m_sfx_to_play.unlock();
|
||||
current->reallyPlayNow();
|
||||
me->m_sfx_to_play.lock();
|
||||
|
||||
} // while
|
||||
|
||||
return NULL;
|
||||
} // mainLoop
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/** Called then sound is globally switched on or off. It either pauses or
|
||||
|
@ -110,15 +110,21 @@ private:
|
||||
/** Master gain value, taken from the user config value. */
|
||||
float m_master_gain;
|
||||
|
||||
/** Thread id of the thread running in this object. */
|
||||
Synchronised<pthread_t *> m_thread_id;
|
||||
|
||||
/** A conditional variable to wake up the main loop. */
|
||||
pthread_cond_t m_cond_request;
|
||||
|
||||
void loadSfx();
|
||||
SFXManager();
|
||||
virtual ~SFXManager();
|
||||
|
||||
static void* mainLoop(void *obj);
|
||||
public:
|
||||
static void create();
|
||||
static void destroy();
|
||||
void queue(SFXBase *sfx);
|
||||
void update();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Static function to get the singleton sfx manager. */
|
||||
static SFXManager *get()
|
||||
@ -128,6 +134,7 @@ public:
|
||||
} // get
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void stopThread();
|
||||
bool sfxAllowed();
|
||||
SFXBuffer* loadSingleSfx(const XMLNode* node,
|
||||
const std::string &path=std::string(""),
|
||||
|
@ -1413,8 +1413,6 @@ int main(int argc, char *argv[] )
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
return 0 ;
|
||||
} // main
|
||||
|
||||
@ -1439,6 +1437,7 @@ static void cleanSuperTuxKart()
|
||||
if(Online::RequestManager::isRunning())
|
||||
Online::RequestManager::get()->stopNetworkThread();
|
||||
|
||||
SFXManager::get()->stopThread();
|
||||
irr_driver->updateConfigIfRelevant();
|
||||
AchievementsManager::destroy();
|
||||
Referee::cleanup();
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
@ -140,7 +139,6 @@ void MainLoop::run()
|
||||
{
|
||||
PROFILER_PUSH_CPU_MARKER("Music/input/GUI", 0x7F, 0x00, 0x00);
|
||||
music_manager->update(dt);
|
||||
SFXManager::get()->update();
|
||||
input_manager->update(dt);
|
||||
|
||||
#ifdef ENABLE_WIIUSE
|
||||
|
Loading…
Reference in New Issue
Block a user