675 lines
16 KiB
C++
675 lines
16 KiB
C++
|
|
#include "fmod_settings.h"
|
||
|
|
|
||
|
|
#ifdef FMOD_SUPPORT_NONBLOCKING
|
||
|
|
|
||
|
|
#include "fmod_async.h"
|
||
|
|
#include "fmod_dspi.h"
|
||
|
|
#include "fmod_soundi.h"
|
||
|
|
#include "fmod_systemi.h"
|
||
|
|
|
||
|
|
namespace FMOD
|
||
|
|
{
|
||
|
|
|
||
|
|
LinkedListNode AsyncThread::gAsyncHead;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
void asyncThreadFunc(void *data)
|
||
|
|
{
|
||
|
|
AsyncThread *asyncThread = (AsyncThread *)data;
|
||
|
|
asyncThread->threadFunc();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
AsyncThread::AsyncThread()
|
||
|
|
{
|
||
|
|
mCrit = 0;
|
||
|
|
mThreadActive = false;
|
||
|
|
mBusy = false;
|
||
|
|
mDone = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::shutDown()
|
||
|
|
{
|
||
|
|
if (FMOD::gGlobal->gAsyncCrit)
|
||
|
|
{
|
||
|
|
AsyncThread *asyncthread;
|
||
|
|
LinkedListNode *current, *next;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
{
|
||
|
|
current = gAsyncHead.getNext();
|
||
|
|
while (current != &gAsyncHead)
|
||
|
|
{
|
||
|
|
next = current->getNext();
|
||
|
|
|
||
|
|
asyncthread = SAFE_CAST(AsyncThread, current);
|
||
|
|
asyncthread->reallyRelease();
|
||
|
|
|
||
|
|
current = next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::addCallback(FMOD_ASYNC_CALLBACK callback, AsyncThread **asyncthread)
|
||
|
|
{
|
||
|
|
FMOD_RESULT result;
|
||
|
|
|
||
|
|
if (asyncthread)
|
||
|
|
{
|
||
|
|
*asyncthread = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
LinkedListNode *node = (LinkedListNode *)FMOD_Object_Alloc(LinkedListNode);
|
||
|
|
if (!node)
|
||
|
|
{
|
||
|
|
return FMOD_ERR_MEMORY;
|
||
|
|
}
|
||
|
|
|
||
|
|
node->setData((void *)callback);
|
||
|
|
|
||
|
|
/*
|
||
|
|
Make sure there's a thread for us
|
||
|
|
*/
|
||
|
|
result = getAsyncThread(0);
|
||
|
|
if (result != FMOD_OK)
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
LinkedListNode *threadnode = gAsyncHead.getNext();
|
||
|
|
if (threadnode != &gAsyncHead)
|
||
|
|
{
|
||
|
|
AsyncThread *thread = SAFE_CAST(AsyncThread, threadnode);
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
{
|
||
|
|
node->addBefore(&thread->mCallbackHead);
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
|
||
|
|
if (asyncthread)
|
||
|
|
{
|
||
|
|
*asyncthread = thread;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return FMOD_ERR_INTERNAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::removeCallback(FMOD_ASYNC_CALLBACK callback)
|
||
|
|
{
|
||
|
|
LinkedListNode *threadnode = gAsyncHead.getNext();
|
||
|
|
|
||
|
|
if (threadnode != &gAsyncHead)
|
||
|
|
{
|
||
|
|
AsyncThread *asyncthread = SAFE_CAST(AsyncThread, threadnode);
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
|
||
|
|
LinkedListNode *callbacknode = asyncthread->mCallbackHead.getNext();
|
||
|
|
for (; callbacknode != &asyncthread->mCallbackHead; callbacknode = callbacknode->getNext())
|
||
|
|
{
|
||
|
|
if (callbacknode->getData() == (void *)callback)
|
||
|
|
{
|
||
|
|
callbacknode->removeNode();
|
||
|
|
FMOD_Memory_Free(callbacknode);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return FMOD_ERR_INTERNAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::init(bool owned, SystemI *system)
|
||
|
|
{
|
||
|
|
FMOD_RESULT result;
|
||
|
|
|
||
|
|
mOwned = owned;
|
||
|
|
|
||
|
|
result = FMOD_OS_CriticalSection_Create(&mCrit);
|
||
|
|
if (result != FMOD_OK)
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
result = mThread.initThread("FMOD thread for FMOD_NONBLOCKING", asyncThreadFunc, this, ASYNC_THREADPRIORITY, 0, ASYNC_STACKSIZE, true, 0, system);
|
||
|
|
if (result != FMOD_OK)
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
mThreadActive = true;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
addBefore(&gAsyncHead);
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::init", "created thread for %p %s\n", this, mOwned ? "(owned)" : ""));
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::release()
|
||
|
|
{
|
||
|
|
if (mOwned)
|
||
|
|
{
|
||
|
|
if (mHead.getNext() != &mHead)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::release", "%p queue not empty\n", this));
|
||
|
|
}
|
||
|
|
|
||
|
|
mDone = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::reallyRelease()
|
||
|
|
{
|
||
|
|
FMOD_OS_CriticalSection_Enter(mCrit);
|
||
|
|
{
|
||
|
|
if (mHead.getNext() != &mHead)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "%p queue not empty\n", this));
|
||
|
|
}
|
||
|
|
if (mBusy)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "%p still busy\n", this));
|
||
|
|
}
|
||
|
|
|
||
|
|
LinkedListNode *next, *current = mCallbackHead.getNext();
|
||
|
|
while (current != &mCallbackHead)
|
||
|
|
{
|
||
|
|
next = current->getNext();
|
||
|
|
current->removeNode();
|
||
|
|
FMOD_Memory_Free(current);
|
||
|
|
current = next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(mCrit);
|
||
|
|
|
||
|
|
// FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
removeNode();
|
||
|
|
// FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
|
||
|
|
mThreadActive = false;
|
||
|
|
mThread.closeThread();
|
||
|
|
|
||
|
|
if (mCrit)
|
||
|
|
{
|
||
|
|
FMOD_OS_CriticalSection_Free(mCrit);
|
||
|
|
}
|
||
|
|
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "released thread for %p %s\n", this, mOwned ? "(owned)" : ""));
|
||
|
|
|
||
|
|
FMOD_Memory_Free(this);
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::wakeupThread()
|
||
|
|
{
|
||
|
|
return mThread.wakeupThread();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::update()
|
||
|
|
{
|
||
|
|
if (FMOD::gGlobal->gAsyncCrit)
|
||
|
|
{
|
||
|
|
AsyncThread *asyncthread;
|
||
|
|
LinkedListNode *current, *next;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
{
|
||
|
|
current = gAsyncHead.getNext();
|
||
|
|
while (current != &gAsyncHead)
|
||
|
|
{
|
||
|
|
next = current->getNext();
|
||
|
|
|
||
|
|
asyncthread = SAFE_CAST(AsyncThread, current);
|
||
|
|
if (asyncthread->mDone)
|
||
|
|
{
|
||
|
|
asyncthread->reallyRelease();
|
||
|
|
}
|
||
|
|
|
||
|
|
current = next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::threadFunc()
|
||
|
|
{
|
||
|
|
FMOD_RESULT result = FMOD_OK;
|
||
|
|
SoundI *sound = 0;
|
||
|
|
SystemI *system;
|
||
|
|
LinkedListNode *current;
|
||
|
|
|
||
|
|
if (mThreadActive)
|
||
|
|
{
|
||
|
|
FMOD_OS_CriticalSection_Enter(mCrit);
|
||
|
|
{
|
||
|
|
current = mHead.getNext();
|
||
|
|
if (current != &mHead)
|
||
|
|
{
|
||
|
|
sound = (SoundI *)current->getData();
|
||
|
|
current->removeNode();
|
||
|
|
mBusy = true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
current = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(mCrit);
|
||
|
|
|
||
|
|
if (sound)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "Starting Asynchronous operation on sound %p\n", sound));
|
||
|
|
FLOG_INDENT(4);
|
||
|
|
|
||
|
|
system = sound->mSystem;
|
||
|
|
|
||
|
|
if (sound->mOpenState == FMOD_OPENSTATE_LOADING)
|
||
|
|
{
|
||
|
|
if (sound->mMode & (FMOD_OPENMEMORY | FMOD_OPENMEMORY_POINT))
|
||
|
|
{
|
||
|
|
result = system->createSoundInternal((const char *)sound->mAsyncData->mNameData, sound->mMode, sound->mAsyncData->mBufferSize, sound->mAsyncData->mBufferSizeType, sound->mAsyncData->mExInfoExists ? &sound->mAsyncData->mExInfo : 0, true, &sound);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
result = system->createSoundInternal(sound->mAsyncData->mName, sound->mMode, sound->mAsyncData->mBufferSize, sound->mAsyncData->mBufferSizeType, sound->mAsyncData->mExInfoExists ? &sound->mAsyncData->mExInfo : 0, true, &sound);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef FMOD_SUPPORT_STREAMING
|
||
|
|
#ifdef FMOD_SUPPORT_NONBLOCKSETPOS
|
||
|
|
else if (sound->mOpenState == FMOD_OPENSTATE_SETPOSITION)
|
||
|
|
{
|
||
|
|
Stream *stream = SAFE_CAST(Stream, sound);
|
||
|
|
|
||
|
|
/*
|
||
|
|
Block here and wait for stream thread to stop doing stuff.
|
||
|
|
*/
|
||
|
|
while (!(stream->mFlags & (FMOD_SOUND_FLAG_SETPOS_SAFE | FMOD_SOUND_FLAG_THREADFINISHED)))
|
||
|
|
{
|
||
|
|
FMOD_OS_Time_Sleep(10);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!(stream->mFlags & FMOD_SOUND_FLAG_THREADFINISHED))
|
||
|
|
{
|
||
|
|
result = stream->mChannel->setPositionEx(sound->mAsyncData->mPosition, sound->mAsyncData->mPositionType, true);
|
||
|
|
if (result == FMOD_OK)
|
||
|
|
{
|
||
|
|
stream->mChannel->mFlags &= ~CHANNELREAL_FLAG_PAUSEDFORSETPOS;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(sound->mSystem->mStreamRealchanCrit);
|
||
|
|
if (stream->mChannel->mRealChannel[0])
|
||
|
|
{
|
||
|
|
stream->mChannel->setPaused(stream->mChannel->mFlags & CHANNELREAL_FLAG_PAUSED ? true : false);
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(sound->mSystem->mStreamRealchanCrit);
|
||
|
|
}
|
||
|
|
else if (result == FMOD_ERR_INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
result = FMOD_OK;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
else if (sound->mOpenState == FMOD_OPENSTATE_SEEKING)
|
||
|
|
{
|
||
|
|
Stream *stream = SAFE_CAST(Stream, sound);
|
||
|
|
|
||
|
|
if (stream->mSubSoundList)
|
||
|
|
{
|
||
|
|
result = FMOD_OK;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
result = stream->updateSubSound(stream->mSubSoundIndex, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (result == FMOD_OK)
|
||
|
|
{
|
||
|
|
result = stream->setPosition(0, FMOD_TIMEUNIT_PCM);
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "done setposition\n"));
|
||
|
|
if (result == FMOD_OK)
|
||
|
|
{
|
||
|
|
result = stream->flush();
|
||
|
|
if (result == FMOD_OK)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "done flush\n"));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "stream->flush returned %d\n", result));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "stream->setPosition returned %d\n", result));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
else
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "AsyncThread::threadFunc: unexpected mOpenState (%d). Result = %d\n", sound->mOpenState, result));
|
||
|
|
}
|
||
|
|
|
||
|
|
sound->mAsyncData->mResult = result;
|
||
|
|
sound->mFlags |= FMOD_SOUND_FLAG_DONOTRELEASE; /* Dissalow release... */
|
||
|
|
sound->mOpenState = (result == FMOD_OK) ? FMOD_OPENSTATE_READY : FMOD_OPENSTATE_ERROR; /* .. but allow everything else. */
|
||
|
|
if (sound->mSubSoundParent)
|
||
|
|
{
|
||
|
|
sound->mSubSoundParent->mOpenState = sound->mOpenState;
|
||
|
|
}
|
||
|
|
if (sound->mSubSoundShared)
|
||
|
|
{
|
||
|
|
sound->mSubSoundShared->mOpenState = sound->mOpenState;
|
||
|
|
}
|
||
|
|
mBusy = false;
|
||
|
|
|
||
|
|
if (sound->mAsyncData->mExInfoExists)
|
||
|
|
{
|
||
|
|
if (sound->mAsyncData->mExInfo.nonblockcallback)
|
||
|
|
{
|
||
|
|
sound->mUserData = sound->mAsyncData->mExInfo.userdata;
|
||
|
|
|
||
|
|
sound->mAsyncData->mExInfo.nonblockcallback((FMOD_SOUND *)sound, result);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
sound->mFlags &= ~FMOD_SOUND_FLAG_DONOTRELEASE;
|
||
|
|
|
||
|
|
/*
|
||
|
|
Release this thread if it's owned
|
||
|
|
*/
|
||
|
|
release();
|
||
|
|
|
||
|
|
FLOG_INDENT(-4);
|
||
|
|
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "Finished Asynchronous operation on sound %p\n", sound));
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Call any callbacks that have been added
|
||
|
|
*/
|
||
|
|
LinkedListNode *node;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(mCrit);
|
||
|
|
{
|
||
|
|
node = mCallbackHead.getNext();
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(mCrit);
|
||
|
|
|
||
|
|
while (node != &mCallbackHead)
|
||
|
|
{
|
||
|
|
FMOD_ASYNC_CALLBACK callback = (FMOD_ASYNC_CALLBACK)node->getData();
|
||
|
|
|
||
|
|
result = callback();
|
||
|
|
if (result != FMOD_OK)
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(mCrit);
|
||
|
|
{
|
||
|
|
node = node->getNext();
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(mCrit);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
[
|
||
|
|
[DESCRIPTION]
|
||
|
|
|
||
|
|
[PARAMETERS]
|
||
|
|
|
||
|
|
[RETURN_VALUE]
|
||
|
|
|
||
|
|
[REMARKS]
|
||
|
|
|
||
|
|
[SEE_ALSO]
|
||
|
|
]
|
||
|
|
*/
|
||
|
|
FMOD_RESULT AsyncThread::getAsyncThread(SoundI *sound)
|
||
|
|
{
|
||
|
|
FMOD_RESULT result;
|
||
|
|
LinkedListNode *current;
|
||
|
|
bool found, owned;
|
||
|
|
AsyncThread *asyncthread = 0;
|
||
|
|
|
||
|
|
owned = false;
|
||
|
|
found = false;
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
{
|
||
|
|
current = gAsyncHead.getNext();
|
||
|
|
if (current != &gAsyncHead)
|
||
|
|
{
|
||
|
|
asyncthread = SAFE_CAST(AsyncThread, current);
|
||
|
|
|
||
|
|
FMOD_OS_CriticalSection_Enter(asyncthread->mCrit);
|
||
|
|
{
|
||
|
|
if (0) //(asyncthread->mHead.getNext() != &asyncthread->mHead) || asyncthread->mBusy || asyncthread->mDone)
|
||
|
|
{
|
||
|
|
owned = true; /* The first asyncthread is or will be busy so make a new one */
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
found = true; /* The first asyncthread isn't doing anything so use it */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(asyncthread->mCrit);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||
|
|
|
||
|
|
if (!found)
|
||
|
|
{
|
||
|
|
asyncthread = FMOD_Object_Alloc(AsyncThread);
|
||
|
|
if (!asyncthread)
|
||
|
|
{
|
||
|
|
return FMOD_ERR_MEMORY;
|
||
|
|
}
|
||
|
|
|
||
|
|
result = asyncthread->init(owned, sound ? sound->mSystem : 0);
|
||
|
|
if (result != FMOD_OK)
|
||
|
|
{
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (sound)
|
||
|
|
{
|
||
|
|
if (sound->mAsyncData->mThread)
|
||
|
|
{
|
||
|
|
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::getAsyncThread", "sound->mAsyncData->Thread not null == %p\n", sound->mAsyncData->mThread));
|
||
|
|
}
|
||
|
|
|
||
|
|
sound->mAsyncData->mThread = asyncthread;
|
||
|
|
}
|
||
|
|
|
||
|
|
return FMOD_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|