Fixes rare crash in sound manager, due to worker thread dereferencing global pointer before it had been assigned. Fixes #2333, refs #2387, #2317.

Fixes potential infinite loop if worker thread was running but not
enabled.
Fixes apparent bug in fading sound smoothness.
Cleans up worker class slightly.
Cleans up weird and inconsistent whitespace.

This was SVN commit r15269.
This commit is contained in:
historic_bruno
2014-06-02 02:09:58 +00:00
parent c17bf75cbb
commit a63ed4e4c4
3 changed files with 169 additions and 202 deletions
+132 -166
View File
@@ -19,21 +19,20 @@
#include "ISoundManager.h"
#include "SoundManager.h"
#include "data/SoundData.h"
#include "items/CBufferItem.h"
#include "items/CSoundItem.h"
#include "items/CStreamItem.h"
#include "ps/Filesystem.h"
#include "soundmanager/data/SoundData.h"
#include "soundmanager/items/CSoundItem.h"
#include "soundmanager/items/CBufferItem.h"
#include "soundmanager/items/CStreamItem.h"
#include "lib/external_libraries/libsdl.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "ps/Filesystem.h"
#include "ps/Profiler2.h"
ISoundManager* g_SoundManager = NULL;
#define SOURCE_NUM 64
#define SOURCE_NUM 64
#if CONFIG2_AUDIO
@@ -47,7 +46,6 @@ public:
m_Items = new ItemsList;
m_DeadItems = new ItemsList;
m_Shutdown = false;
m_Enabled = false;
int ret = pthread_create(&m_WorkerThread, NULL, &RunThread, this);
ENSURE(ret == 0);
@@ -60,22 +58,12 @@ public:
delete m_DeadItems;
}
void SetEnabled(bool enabled)
{
CScopeLock lock(m_WorkerMutex);
if (enabled != m_Enabled)
{
m_Enabled = enabled;
}
}
bool Shutdown()
{
{
CScopeLock lock(m_WorkerMutex);
m_Shutdown = true;
m_Enabled = false;
ItemsList::iterator lstr = m_Items->begin();
while (lstr != m_Items->end())
@@ -91,10 +79,10 @@ public:
return true;
}
void addItem( ISoundItem* anItem )
void addItem(ISoundItem* anItem)
{
CScopeLock lock(m_WorkerMutex);
m_Items->push_back( anItem );
m_Items->push_back(anItem);
}
void CleanupItems()
@@ -103,7 +91,7 @@ public:
AL_CHECK
ItemsList::iterator deadItems = m_DeadItems->begin();
while (deadItems != m_DeadItems->end())
{
{
delete *deadItems;
++deadItems;
@@ -125,20 +113,14 @@ private:
void Run()
{
while ( true )
while (true)
{
g_Profiler2.RecordRegionLeave("semaphore wait");
// Handle shutdown requests as soon as possible
if (GetShutdown())
return;
// If we're not enabled, ignore this wakeup
if (!GetEnabled())
continue;
int pauseTime = 500;
if ( g_SoundManager->InDistress() )
if (g_SoundManager->InDistress())
pauseTime = 50;
{
@@ -147,13 +129,12 @@ private:
ItemsList::iterator lstr = m_Items->begin();
ItemsList* nextItemList = new ItemsList;
while (lstr != m_Items->end()) {
while (lstr != m_Items->end())
{
AL_CHECK
if ((*lstr)->IdleTask())
{
if ( (pauseTime == 1000) && (*lstr)->IsFading() )
if ((pauseTime == 500) && (*lstr)->IsFading())
pauseTime = 100;
nextItemList->push_back(*lstr);
@@ -173,24 +154,16 @@ private:
AL_CHECK
}
SDL_Delay( pauseTime );
SDL_Delay(pauseTime);
}
}
bool GetEnabled()
{
CScopeLock lock(m_WorkerMutex);
return m_Enabled;
}
bool GetShutdown()
{
CScopeLock lock(m_WorkerMutex);
return m_Shutdown;
}
private:
// Thread-related members:
pthread_t m_WorkerThread;
@@ -202,7 +175,6 @@ private:
ItemsList* m_Items;
ItemsList* m_DeadItems;
bool m_Enabled;
bool m_Shutdown;
CSoundManagerWorker(ISoundManager* UNUSED(other)){};
@@ -210,25 +182,24 @@ private:
void ISoundManager::CreateSoundManager()
{
if ( !g_SoundManager )
if (!g_SoundManager)
{
g_SoundManager = new CSoundManager();
g_SoundManager->StartWorker();
}
}
void ISoundManager::SetEnabled(bool doEnable)
{
if ( g_SoundManager && !doEnable )
{
if (g_SoundManager && !doEnable)
SAFE_DELETE(g_SoundManager);
}
else if ( !g_SoundManager && doEnable )
{
else if (!g_SoundManager && doEnable)
ISoundManager::CreateSoundManager();
}
}
void ISoundManager::CloseGame()
{
if ( CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager )
aSndMgr->SetAmbientItem( NULL );
if (CSoundManager* aSndMgr = (CSoundManager*)g_SoundManager)
aSndMgr->SetAmbientItem(NULL);
}
void CSoundManager::al_ReportError(ALenum err, const char* caller, int line)
@@ -257,45 +228,42 @@ Status CSoundManager::ReloadChangedFiles(const VfsPath& UNUSED(path))
CSoundManager::CSoundManager()
{
m_CurrentEnvirons = 0;
m_ALSourceBuffer = NULL;
m_Device = NULL;
m_Context = NULL;
m_Worker = NULL;
m_CurrentEnvirons = NULL;
m_ALSourceBuffer = NULL;
m_Device = NULL;
m_Context = NULL;
m_Worker = NULL;
m_PlayListItems = NULL;
m_CurrentTune = 0;
m_Gain = 1;
m_MusicGain = 1;
m_AmbientGain = 1;
m_ActionGain = 1;
m_CurrentTune = NULL;
m_Gain = 1;
m_MusicGain = 1;
m_AmbientGain = 1;
m_ActionGain = 1;
m_UIGain = 1;
m_BufferCount = 50;
m_BufferSize = 98304;
m_SoundEnabled = true;
m_MusicEnabled = true;
m_MusicPaused = false;
m_AmbientPaused = false;
m_ActionPaused = false;
m_BufferCount = 50;
m_BufferSize = 98304;
m_SoundEnabled = true;
m_MusicEnabled = true;
m_MusicPaused = false;
m_AmbientPaused = false;
m_ActionPaused = false;
m_DistressTime = 0;
m_DistressTime = 0;
m_DistressErrCount = 0;
m_PlayingPlaylist = false;
m_LoopingPlaylist = false;
m_RunningPlaylist = false;
m_PlaylistGap = 0;
m_PlaylistGap = 0;
m_Enabled = false;
AlcInit();
if ( m_Enabled )
if (m_Enabled)
{
InitListener();
m_PlayListItems = new PlayList;
m_Worker = new CSoundManagerWorker();
m_Worker->SetEnabled( true );
}
RegisterFileReloadFunc(ReloadChangedFileCB, this);
@@ -305,7 +273,7 @@ CSoundManager::~CSoundManager()
{
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
if (m_Worker )
if (m_Worker)
{
AL_CHECK
m_Worker->Shutdown();
@@ -321,20 +289,24 @@ CSoundManager::~CSoundManager()
delete it->second;
m_SoundGroups.clear();
if ( m_PlayListItems )
if (m_PlayListItems)
delete m_PlayListItems;
if ( m_ALSourceBuffer != NULL )
if (m_ALSourceBuffer != NULL)
delete[] m_ALSourceBuffer;
if ( m_Context )
if (m_Context)
alcDestroyContext(m_Context);
if ( m_Device )
if (m_Device)
alcCloseDevice(m_Device);
}
void CSoundManager::StartWorker()
{
if (m_Enabled)
m_Worker = new CSoundManagerWorker();
}
Status CSoundManager::AlcInit()
{
@@ -352,17 +324,15 @@ Status CSoundManager::AlcInit()
m_ALSourceBuffer = new ALSourceHolder[SOURCE_NUM];
ALuint* sourceList = new ALuint[SOURCE_NUM];
alGenSources( SOURCE_NUM, sourceList);
alGenSources(SOURCE_NUM, sourceList);
ALCenum err = alcGetError(m_Device);
if ( err == ALC_NO_ERROR )
if (err == ALC_NO_ERROR)
{
for ( int x=0; x<SOURCE_NUM;x++)
for (int x = 0; x < SOURCE_NUM; x++)
{
m_ALSourceBuffer[x].ALSource = sourceList[x];
m_ALSourceBuffer[x].SourceItem = NULL;
m_ALSourceBuffer[x].ALSource = sourceList[x];
m_ALSourceBuffer[x].SourceItem = NULL;
}
m_Enabled = true;
}
@@ -380,14 +350,12 @@ Status CSoundManager::AlcInit()
ALCenum err = alcGetError(m_Device);
const char* dev_name = (const char*)alcGetString(m_Device, ALC_DEVICE_SPECIFIER);
if(err == ALC_NO_ERROR && m_Device && m_Context)
if (err == ALC_NO_ERROR && m_Device && m_Context)
debug_printf(L"Sound: AlcInit success, using %hs\n", dev_name);
else
{
LOGERROR(L"Sound: AlcInit failed, m_Device=%p m_Context=%p dev_name=%hs err=%x\n", m_Device, m_Context, dev_name, err);
// FIXME Hack to get around exclusive access to the sound device
#if OS_UNIX
ret = INFO::OK;
@@ -403,9 +371,9 @@ bool CSoundManager::InDistress()
{
CScopeLock lock(m_DistressMutex);
if ( m_DistressTime == 0 )
if (m_DistressTime == 0)
return false;
else if ( (timer_Time() - m_DistressTime) > 10 )
else if ((timer_Time() - m_DistressTime) > 10)
{
m_DistressTime = 0;
// Coming out of distress mode
@@ -437,11 +405,11 @@ void CSoundManager::SetDistressThroughError()
ALuint CSoundManager::GetALSource( ISoundItem* anItem)
ALuint CSoundManager::GetALSource(ISoundItem* anItem)
{
for ( int x=0; x<SOURCE_NUM;x++)
for (int x = 0; x < SOURCE_NUM; x++)
{
if ( ! m_ALSourceBuffer[x].SourceItem )
if (!m_ALSourceBuffer[x].SourceItem)
{
m_ALSourceBuffer[x].SourceItem = anItem;
return m_ALSourceBuffer[x].ALSource;
@@ -453,9 +421,9 @@ ALuint CSoundManager::GetALSource( ISoundItem* anItem)
void CSoundManager::ReleaseALSource(ALuint theSource)
{
for ( int x=0; x<SOURCE_NUM;x++)
for (int x = 0; x < SOURCE_NUM; x++)
{
if ( m_ALSourceBuffer[x].ALSource == theSource )
if (m_ALSourceBuffer[x].ALSource == theSource)
{
m_ALSourceBuffer[x].SourceItem = NULL;
return;
@@ -482,8 +450,8 @@ void CSoundManager::ClearPlayListItems()
{
if (m_Enabled)
{
if ( m_PlayingPlaylist )
SetMusicItem( NULL );
if (m_PlayingPlaylist)
SetMusicItem(NULL);
m_PlayingPlaylist = false;
m_LoopingPlaylist = false;
@@ -493,7 +461,7 @@ void CSoundManager::ClearPlayListItems()
}
}
void CSoundManager::StartPlayList( bool doLoop )
void CSoundManager::StartPlayList(bool doLoop)
{
if (m_Enabled && m_MusicEnabled)
{
@@ -502,8 +470,8 @@ void CSoundManager::StartPlayList( bool doLoop )
m_PlayingPlaylist = true;
m_LoopingPlaylist = doLoop;
m_RunningPlaylist = false;
ISoundItem* aSnd = LoadItem( (m_PlayListItems->at( 0 )) );
ISoundItem* aSnd = LoadItem((m_PlayListItems->at(0)));
if (aSnd)
SetMusicItem(aSnd);
else
@@ -514,10 +482,10 @@ void CSoundManager::StartPlayList( bool doLoop )
void CSoundManager::SetMasterGain(float gain)
{
if ( m_Enabled )
if (m_Enabled)
{
m_Gain = gain;
alListenerf( AL_GAIN, m_Gain);
alListenerf(AL_GAIN, m_Gain);
AL_CHECK
}
}
@@ -544,13 +512,13 @@ ISoundItem* CSoundManager::LoadItem(const VfsPath& itemPath)
{
AL_CHECK
if ( m_Enabled )
if (m_Enabled)
{
CSoundData* itemData = CSoundData::SoundDataFromFile(itemPath);
AL_CHECK
if ( itemData )
return CSoundManager::ItemForData( itemData );
if (itemData)
return CSoundManager::ItemForData(itemData);
}
return NULL;
@@ -563,7 +531,7 @@ ISoundItem* CSoundManager::ItemForData(CSoundData* itemData)
AL_CHECK
if ( m_Enabled && (itemData != NULL) )
if (m_Enabled && (itemData != NULL))
{
if (itemData->IsOneShot())
{
@@ -577,46 +545,45 @@ ISoundItem* CSoundManager::ItemForData(CSoundData* itemData)
answer = new CStreamItem(itemData);
}
if ( answer && m_Worker )
m_Worker->addItem( answer );
if (answer && m_Worker)
m_Worker->addItem(answer);
}
return answer;
}
void CSoundManager::IdleTask()
{
if ( m_Enabled )
if (m_Enabled)
{
if (m_CurrentTune)
{
m_CurrentTune->EnsurePlay();
if ( m_PlayingPlaylist && m_RunningPlaylist )
if (m_PlayingPlaylist && m_RunningPlaylist)
{
if ( m_CurrentTune->Finished() )
if (m_CurrentTune->Finished())
{
if ( m_PlaylistGap == 0 )
if (m_PlaylistGap == 0)
{
m_PlaylistGap = timer_Time() + 15;
}
else if ( m_PlaylistGap < timer_Time() )
else if (m_PlaylistGap < timer_Time())
{
m_PlaylistGap = 0;
PlayList::iterator it = find (m_PlayListItems->begin(), m_PlayListItems->end(), *(m_CurrentTune->GetName()) );
if ( it != m_PlayListItems->end() )
PlayList::iterator it = find(m_PlayListItems->begin(), m_PlayListItems->end(), *(m_CurrentTune->GetName()));
if (it != m_PlayListItems->end())
{
++it;
Path nextPath;
if ( it == m_PlayListItems->end() )
nextPath = m_PlayListItems->at( 0 );
if (it == m_PlayListItems->end())
nextPath = m_PlayListItems->at(0);
else
nextPath = *it;
ISoundItem* aSnd = LoadItem( nextPath );
if ( aSnd )
SetMusicItem( aSnd );
ISoundItem* aSnd = LoadItem(nextPath);
if (aSnd)
SetMusicItem(aSnd);
}
}
}
@@ -628,16 +595,15 @@ void CSoundManager::IdleTask()
if (m_Worker)
m_Worker->CleanupItems();
}
}
ISoundItem* CSoundManager::ItemForEntity( entity_id_t UNUSED(source), CSoundData* sndData)
ISoundItem* CSoundManager::ItemForEntity(entity_id_t UNUSED(source), CSoundData* sndData)
{
ISoundItem* currentItem = NULL;
if ( m_Enabled )
currentItem = ItemForData( sndData );
if (m_Enabled)
currentItem = ItemForData(sndData);
return currentItem;
}
@@ -645,22 +611,23 @@ ISoundItem* CSoundManager::ItemForEntity( entity_id_t UNUSED(source), CSoundData
void CSoundManager::InitListener()
{
ALfloat listenerPos[]={0.0,0.0,0.0};
ALfloat listenerVel[]={0.0,0.0,0.0};
ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
ALfloat listenerPos[] = {0.0, 0.0, 0.0};
ALfloat listenerVel[] = {0.0, 0.0, 0.0};
ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};
alListenerfv(AL_POSITION,listenerPos);
alListenerfv(AL_VELOCITY,listenerVel);
alListenerfv(AL_ORIENTATION,listenerOri);
alListenerfv(AL_POSITION, listenerPos);
alListenerfv(AL_VELOCITY, listenerVel);
alListenerfv(AL_ORIENTATION, listenerOri);
alDistanceModel(AL_LINEAR_DISTANCE);
}
void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain )
void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain)
{
if (anItem)
{
if (m_Enabled && (m_ActionGain > 0)) {
if (m_Enabled && (m_ActionGain > 0))
{
anItem->SetGain(m_ActionGain * groupGain);
anItem->PlayAndDelete();
AL_CHECK
@@ -668,12 +635,12 @@ void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain )
}
}
void CSoundManager::SetMusicEnabled (bool isEnabled)
void CSoundManager::SetMusicEnabled(bool isEnabled)
{
if (m_CurrentTune && !isEnabled)
{
m_CurrentTune->FadeAndDelete(1.00);
m_CurrentTune = 0L;
m_CurrentTune = NULL;
}
m_MusicEnabled = isEnabled;
}
@@ -685,7 +652,7 @@ void CSoundManager::PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, e
if (m_SoundGroups.find(groupPath.string()) == m_SoundGroups.end())
{
group = new CSoundGroup();
if (!group->LoadSoundGroup(L"audio/" + groupPath.string() ))
if (!group->LoadSoundGroup(L"audio/" + groupPath.string()))
{
LOGERROR(L"Failed to load sound group '%ls'", groupPath.string().c_str());
delete group;
@@ -700,11 +667,11 @@ void CSoundManager::PlayAsGroup(const VfsPath& groupPath, CVector3D sourcePos, e
}
// Failed to load group -> do nothing
if ( group && ( ownedSound || !group->TestFlag( eOwnerOnly ) ) )
if (group && (ownedSound || !group->TestFlag(eOwnerOnly)))
group->PlayNext(sourcePos, source);
}
void CSoundManager::PlayAsMusic( const VfsPath& itemPath, bool looping )
void CSoundManager::PlayAsMusic(const VfsPath& itemPath, bool looping)
{
if (m_Enabled)
{
@@ -716,14 +683,14 @@ void CSoundManager::PlayAsMusic( const VfsPath& itemPath, bool looping )
}
}
void CSoundManager::PlayAsAmbient( const VfsPath& itemPath, bool looping )
void CSoundManager::PlayAsAmbient(const VfsPath& itemPath, bool looping)
{
if (m_Enabled)
{
UNUSED2( looping );
UNUSED2(looping);
ISoundItem* aSnd = LoadItem(itemPath);
if (aSnd != NULL)
SetAmbientItem( aSnd );
SetAmbientItem(aSnd);
}
}
@@ -739,7 +706,7 @@ void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping)
if (m_UIGain > 0)
{
anItem->SetGain(m_UIGain);
anItem->SetLooping( looping );
anItem->SetLooping(looping);
anItem->PlayAndDelete();
}
}
@@ -747,42 +714,41 @@ void CSoundManager::PlayAsUI(const VfsPath& itemPath, bool looping)
}
}
void CSoundManager::Pause(bool pauseIt)
{
PauseMusic(pauseIt);
PauseAmbient(pauseIt);
PauseAction(pauseIt);
PauseMusic(pauseIt);
PauseAmbient(pauseIt);
PauseAction(pauseIt);
}
void CSoundManager::PauseMusic (bool pauseIt)
void CSoundManager::PauseMusic(bool pauseIt)
{
if (m_CurrentTune && pauseIt && !m_MusicPaused )
if (m_CurrentTune && pauseIt && !m_MusicPaused)
{
m_CurrentTune->FadeAndPause( 1.0 );
m_CurrentTune->FadeAndPause(1.0);
}
else if ( m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled )
else if (m_CurrentTune && m_MusicPaused && !pauseIt && m_MusicEnabled)
{
m_CurrentTune->SetGain(0);
m_CurrentTune->Resume();
m_CurrentTune->FadeToIn( m_MusicGain, 1.0);
m_CurrentTune->FadeToIn(m_MusicGain, 1.0);
}
m_MusicPaused = pauseIt;
}
void CSoundManager::PauseAmbient (bool pauseIt)
void CSoundManager::PauseAmbient(bool pauseIt)
{
if (m_CurrentEnvirons && pauseIt)
m_CurrentEnvirons->Pause();
else if ( m_CurrentEnvirons )
m_CurrentEnvirons->Resume();
if (m_CurrentEnvirons && pauseIt)
m_CurrentEnvirons->Pause();
else if (m_CurrentEnvirons)
m_CurrentEnvirons->Resume();
m_AmbientPaused = pauseIt;
m_AmbientPaused = pauseIt;
}
void CSoundManager::PauseAction (bool pauseIt)
void CSoundManager::PauseAction(bool pauseIt)
{
m_ActionPaused = pauseIt;
m_ActionPaused = pauseIt;
}
void CSoundManager::SetMusicItem(ISoundItem* anItem)
@@ -793,7 +759,7 @@ void CSoundManager::SetMusicItem(ISoundItem* anItem)
if (m_CurrentTune)
{
m_CurrentTune->FadeAndDelete(2.00);
m_CurrentTune = 0L;
m_CurrentTune = NULL;
}
IdleTask();
@@ -814,7 +780,7 @@ void CSoundManager::SetMusicItem(ISoundItem* anItem)
m_CurrentTune->PlayLoop();
m_MusicPaused = false;
m_CurrentTune->FadeToIn( m_MusicGain, 1.00);
m_CurrentTune->FadeToIn(m_MusicGain, 1.00);
}
else
{
@@ -832,7 +798,7 @@ void CSoundManager::SetAmbientItem(ISoundItem* anItem)
if (m_CurrentEnvirons)
{
m_CurrentEnvirons->FadeAndDelete(3.00);
m_CurrentEnvirons = 0L;
m_CurrentEnvirons = NULL;
}
IdleTask();
@@ -843,7 +809,7 @@ void CSoundManager::SetAmbientItem(ISoundItem* anItem)
m_CurrentEnvirons = anItem;
m_CurrentEnvirons->SetGain(0);
m_CurrentEnvirons->PlayLoop();
m_CurrentEnvirons->FadeToIn( m_AmbientGain, 2.00);
m_CurrentEnvirons->FadeToIn(m_AmbientGain, 2.00);
}
}
AL_CHECK