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 "io/file_manager.hpp"
|
||||||
#include "race/race_manager.hpp"
|
#include "race/race_manager.hpp"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -68,6 +69,7 @@ void SFXManager::destroy()
|
|||||||
*/
|
*/
|
||||||
SFXManager::SFXManager()
|
SFXManager::SFXManager()
|
||||||
{
|
{
|
||||||
|
|
||||||
// The sound manager initialises OpenAL
|
// The sound manager initialises OpenAL
|
||||||
m_initialized = music_manager->initialized();
|
m_initialized = music_manager->initialized();
|
||||||
m_master_gain = UserConfigParams::m_sfx_volume;
|
m_master_gain = UserConfigParams::m_sfx_volume;
|
||||||
@ -75,11 +77,39 @@ SFXManager::SFXManager()
|
|||||||
m_position = Vec3(0,0,0);
|
m_position = Vec3(0,0,0);
|
||||||
|
|
||||||
loadSfx();
|
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;
|
if (!sfxAllowed()) return;
|
||||||
|
|
||||||
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
|
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
|
||||||
m_sfx_to_play.lock();
|
m_sfx_to_play.lock();
|
||||||
m_sfx_to_play.getData().clear();
|
m_sfx_to_play.getData().clear();
|
||||||
m_sfx_to_play.unlock();
|
m_sfx_to_play.unlock();
|
||||||
|
|
||||||
} // SoundManager
|
} // SoundManager
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -87,6 +117,12 @@ SFXManager::SFXManager()
|
|||||||
*/
|
*/
|
||||||
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
|
// ---- clear m_all_sfx
|
||||||
const int sfx_amount = m_all_sfx.size();
|
const int sfx_amount = m_all_sfx.size();
|
||||||
for (int n=0; n<sfx_amount; n++)
|
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
|
// Don't add sfx that are either not working correctly (e.g. because sfx
|
||||||
// are disabled);
|
// are disabled);
|
||||||
if(sfx->getStatus()==SFX_UNKNOWN ) return;
|
if(sfx && sfx->getStatus()==SFX_UNKNOWN ) return;
|
||||||
|
|
||||||
m_sfx_to_play.lock();
|
m_sfx_to_play.lock();
|
||||||
m_sfx_to_play.getData().push_back(sfx);
|
m_sfx_to_play.getData().push_back(sfx);
|
||||||
m_sfx_to_play.unlock();
|
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();
|
queue(NULL);
|
||||||
while(!m_sfx_to_play.getData().empty())
|
} // 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();
|
bool empty = me->m_sfx_to_play.getData().empty();
|
||||||
m_sfx_to_play.getData().erase(m_sfx_to_play.getData().begin());
|
|
||||||
m_sfx_to_play.unlock();
|
// Wait in cond_wait for a request to arrive. The 'while' is necessary
|
||||||
sfx->reallyPlayNow();
|
// since "spurious wakeups from the pthread_cond_wait ... may occur"
|
||||||
m_sfx_to_play.lock();
|
// (pthread_cond_wait man page)!
|
||||||
} // while !empty
|
while (empty)
|
||||||
m_sfx_to_play.unlock();
|
{
|
||||||
} // update
|
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
|
/** 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. */
|
/** Master gain value, taken from the user config value. */
|
||||||
float m_master_gain;
|
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();
|
void loadSfx();
|
||||||
SFXManager();
|
SFXManager();
|
||||||
virtual ~SFXManager();
|
virtual ~SFXManager();
|
||||||
|
|
||||||
|
static void* mainLoop(void *obj);
|
||||||
public:
|
public:
|
||||||
static void create();
|
static void create();
|
||||||
static void destroy();
|
static void destroy();
|
||||||
void queue(SFXBase *sfx);
|
void queue(SFXBase *sfx);
|
||||||
void update();
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Static function to get the singleton sfx manager. */
|
/** Static function to get the singleton sfx manager. */
|
||||||
static SFXManager *get()
|
static SFXManager *get()
|
||||||
@ -128,6 +134,7 @@ public:
|
|||||||
} // get
|
} // get
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
void stopThread();
|
||||||
bool sfxAllowed();
|
bool sfxAllowed();
|
||||||
SFXBuffer* loadSingleSfx(const XMLNode* node,
|
SFXBuffer* loadSingleSfx(const XMLNode* node,
|
||||||
const std::string &path=std::string(""),
|
const std::string &path=std::string(""),
|
||||||
|
@ -1413,8 +1413,6 @@ int main(int argc, char *argv[] )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0 ;
|
return 0 ;
|
||||||
} // main
|
} // main
|
||||||
|
|
||||||
@ -1439,6 +1437,7 @@ static void cleanSuperTuxKart()
|
|||||||
if(Online::RequestManager::isRunning())
|
if(Online::RequestManager::isRunning())
|
||||||
Online::RequestManager::get()->stopNetworkThread();
|
Online::RequestManager::get()->stopNetworkThread();
|
||||||
|
|
||||||
|
SFXManager::get()->stopThread();
|
||||||
irr_driver->updateConfigIfRelevant();
|
irr_driver->updateConfigIfRelevant();
|
||||||
AchievementsManager::destroy();
|
AchievementsManager::destroy();
|
||||||
Referee::cleanup();
|
Referee::cleanup();
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "audio/music_manager.hpp"
|
#include "audio/music_manager.hpp"
|
||||||
#include "audio/sfx_manager.hpp"
|
|
||||||
#include "config/user_config.hpp"
|
#include "config/user_config.hpp"
|
||||||
#include "graphics/irr_driver.hpp"
|
#include "graphics/irr_driver.hpp"
|
||||||
#include "graphics/material_manager.hpp"
|
#include "graphics/material_manager.hpp"
|
||||||
@ -140,7 +139,6 @@ void MainLoop::run()
|
|||||||
{
|
{
|
||||||
PROFILER_PUSH_CPU_MARKER("Music/input/GUI", 0x7F, 0x00, 0x00);
|
PROFILER_PUSH_CPU_MARKER("Music/input/GUI", 0x7F, 0x00, 0x00);
|
||||||
music_manager->update(dt);
|
music_manager->update(dt);
|
||||||
SFXManager::get()->update();
|
|
||||||
input_manager->update(dt);
|
input_manager->update(dt);
|
||||||
|
|
||||||
#ifdef ENABLE_WIIUSE
|
#ifdef ENABLE_WIIUSE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user