* Init version of new Threading system (next: make threading a runtime option instead of a compile time option)

This commit is contained in:
Murat Suri 2011-05-29 20:32:21 +00:00
parent f3cee669d5
commit 4727870351
10 changed files with 221 additions and 164 deletions

View File

@ -11,10 +11,11 @@
#include "../Headers/cMemoryOverride.h"
#include "../include/cSTLAllocator.h"
#include "../include/cAudioString.h"
#include "../include/IThread.h"
namespace cAudio
{
class cAudioCapture : public IAudioCapture, public cMemoryOverride
class cAudioCapture : public IAudioCapture, public cMemoryOverride, public IThreadWorker
{
public:
@ -38,6 +39,10 @@ namespace cAudio
virtual bool isReady() { return Ready; }
virtual void updateCaptureBuffer(bool force = false);
virtual void shutdown();
virtual bool isUpdateThreadRunning()
{
return (AudioThread != NULL && AudioThread->isRunning());
}
virtual const char* getAvailableDeviceName(unsigned int index);
virtual unsigned int getAvailableDeviceCount();
@ -66,8 +71,13 @@ namespace cAudio
virtual void unRegisterAllEventHandlers();
protected:
virtual void run();
cAudioMutex Mutex;
//! Our update thread
IThread* AudioThread;
bool initOpenALDevice();
void shutdownOpenALDevice();

View File

@ -13,6 +13,7 @@
#include "../Headers/cMemoryOverride.h"
#include "../include/cSTLAllocator.h"
#include "../include/cAudioString.h"
#include "../include/IThread.h"
#include <al.h>
#include <alc.h>
@ -21,7 +22,7 @@ namespace cAudio
{
class IAudioSource;
class cAudioManager : public IAudioManager, public cMemoryOverride
class cAudioManager : public IAudioManager, public cMemoryOverride, public IThreadWorker
{
public:
enum Events{
@ -33,8 +34,8 @@ namespace cAudio
ON_DATASOURCEREGISTER,
};
cAudioManager() : Device(NULL), Context(NULL), EFXSupported(false), Initialized(false) { }
virtual ~cAudioManager() { }
cAudioManager() : Device(NULL), Context(NULL), AudioThread(NULL), EFXSupported(false), Initialized(false) { }
virtual ~cAudioManager();
virtual bool initialize(const char* deviceName = 0x0, int outputFrequency = -1, int eaxEffectSlots = 4);
virtual void shutDown();
@ -72,9 +73,16 @@ namespace cAudio
virtual IListener* getListener() { return &initlistener; }
virtual bool isUpdateThreadRunning()
{
return (AudioThread != NULL && AudioThread->isRunning());
}
#ifdef CAUDIO_EFX_ENABLED
virtual IAudioEffects* getEffects() { return &initEffects; }
#endif
protected:
virtual void run();
private:
//! Mutex for thread syncronization
@ -91,6 +99,9 @@ namespace cAudio
//! Whether the manager is currently initialized and ready to go.
bool Initialized;
//! Our update thread
IThread* AudioThread;
//! Holds an index for fast searching of audio sources by name
cAudioMap<cAudioString, IAudioSource*>::Type audioIndex;
typedef cAudioMap<cAudioString, IAudioSource*>::Type::iterator audioIndexIterator;

View File

@ -5,27 +5,43 @@
#pragma once
#include "../include/cAudioDefines.h"
#include "../Include/IThread.h"
#include "../Headers/cMutex.h"
//Helper defines in order to make sure the function is declared right for use as a thread
#ifdef CAUDIO_PLATFORM_WIN
#define CAUDIO_DECLARE_THREAD_FUNCTION(functionName) unsigned __stdcall functionName( void* arguments )
#else
#define CAUDIO_DECLARE_THREAD_FUNCTION(functionName) void* functionName( void* arguments )
#endif
#ifdef CAUDIO_PLATFORM_WIN
#include <windows.h> //Basic windows includes
#include <process.h>
#else
#include <pthread.h> //Assumed linux system
#endif
namespace cAudio
{
class cAudioThread
class cAudioThread : public IThread
{
public:
// Really basic function to spawn a single detached thread
/** \param start_address The function you want to call
// \param arg Any arguments to pass to the function
// \return 0 if successful, otherwise an error */
cAudioThread(IThreadWorker* pWorker);
~cAudioThread();
virtual bool start();
virtual void join();
virtual void shutdown();
virtual bool isRunning();
protected:
void updateLoop();
#ifdef CAUDIO_PLATFORM_WIN
static int SpawnThread( unsigned __stdcall start_address( void* ), void *arg);
static unsigned int __stdcall threadFunc(void *args);
HANDLE ThreadHandle;
#else
static int SpawnThread( void* start_address( void* ), void *arg);
static void* threadFunc(void* args);
pthread_t ThreadHandle;
#endif
IThreadWorker* Worker;
unsigned int ThreadID;
cAudioMutex Mutex;
bool IsInit;
bool Loop;
};
};

View File

@ -35,6 +35,7 @@ set (file_root_include
include/cAudioString.h
include/cSTLAllocator.h
include/EAudioFormats.h
include/IThread.h
include/IAudioCapture.h
include/IAudioDecoder.h
include/IAudioDecoderFactory.h

View File

@ -36,6 +36,13 @@ namespace cAudio
//! Shuts down the capture device, clearing the internal buffer and setting the audio capture into an uninitialized state. You must call initialize() again in order to reuse this object.
virtual void shutdown() = 0;
//! Returns if the thread used to update all Audio Capture Objects is running.
/** Note: Will always return false if threading is disabled.
The library automatically shuts down the thread if no Audio Capture objects exist and will restart the thread on creation of a new object.
\return True if the thread is currently running, false otherwise.
*/
virtual bool isUpdateThreadRunning() = 0;
//! Returns the name of an available capture device.
/** \param index: Specify which name to retrieve ( Range: 0 to getAvailableDeviceCount()-1 ).
\return Name of the selected device. */
@ -122,11 +129,4 @@ namespace cAudio
\param capture: The object to destroy
*/
CAUDIO_API void destroyAudioCapture(IAudioCapture* capture);
//! Returns if the thread used to update all Audio Capture Objects is running.
/** Note: Will always return false if threading is disabled.
The library automatically shuts down the thread if no Audio Capture objects exist and will restart the thread on creation of a new object.
\return True if the thread is currently running, false otherwise.
*/
CAUDIO_API bool isAudioCaptureThreadRunning();
};

View File

@ -38,6 +38,13 @@ namespace cAudio
//! If threading is disabled, you must call this function every frame to update the playback buffers of audio sources. Otherwise it should not be called.
virtual void update() = 0;
//! Returns if the thread used to update all Audio Managers is running.
/** Note: Will always return false if threading is disabled.
The library automatically shuts down the thread if no Audio Managers exist and will restart the thread on creation of a new manager.
\return True if the thread is currently running, false otherwise.
*/
virtual bool isUpdateThreadRunning() = 0;
//! Returns an Audio Source by its "name" and NULL if the name is not found
/**
\param name: Name of the audio source to retrieve.
@ -190,11 +197,4 @@ namespace cAudio
\param capture: The object to destroy.
*/
CAUDIO_API void destroyAudioManager(IAudioManager* manager);
//! Returns if the thread used to update all Audio Managers is running.
/** Note: Will always return false if threading is disabled.
The library automatically shuts down the thread if no Audio Managers exist and will restart the thread on creation of a new manager.
\return True if the thread is currently running, false otherwise.
*/
CAUDIO_API bool isAudioManagerThreadRunning();
}

23
cAudio/include/IThread.h Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) 2008-2010 Raynaldo (Wildicv) Rivera, Joshua (Dark_Kilauea) Jones
// This file is part of the "cAudio Engine"
// For conditions of distribution and use, see copyright notice in cAudio.h
#pragma once
namespace cAudio
{
class IThread
{
public:
virtual bool start() = 0;
virtual void join() = 0;
virtual void shutdown() = 0;
virtual bool isRunning() = 0;
};
class IThreadWorker
{
public:
virtual void run() = 0;
};
}

View File

@ -13,33 +13,9 @@
namespace cAudio
{
static bool RunAudioCaptureThread(false);
//Note: OpenAL is threadsafe, so a mutex only needs to protect the class state
#ifdef CAUDIO_USE_INTERNAL_THREAD
static cAudioMutex AudioCaptureObjectsMutex;
static cAudioSet<IAudioCapture*>::Type AudioCaptureObjects;
CAUDIO_DECLARE_THREAD_FUNCTION(AudioCaptureUpdateThread)
{
while(RunAudioCaptureThread)
{
AudioCaptureObjectsMutex.lock();
cAudioSet<IAudioCapture*>::Type::iterator it;
for ( it=AudioCaptureObjects.begin() ; it != AudioCaptureObjects.end(); it++ )
{
(*it)->updateCaptureBuffer();
}
AudioCaptureObjectsMutex.unlock();
cAudioSleep(1);
}
return 0;
}
#endif
cAudioCapture::cAudioCapture() : Frequency(22050), Format(EAF_16BIT_MONO), InternalBufferSize(8192),
SampleSize(2), Supported(false), Ready(false), Capturing(false),
CaptureDevice(NULL)
CaptureDevice(NULL), AudioThread(NULL)
{
checkCaptureExtension();
getAvailableDevices();
@ -49,6 +25,12 @@ namespace cAudio
shutdown();
}
void cAudioCapture::run()
{
updateCaptureBuffer();
cAudioSleep(1);
}
bool cAudioCapture::checkCaptureExtension()
{
cAudioMutexBasicLock lock(Mutex);
@ -106,6 +88,14 @@ namespace cAudio
void cAudioCapture::shutdown()
{
cAudioMutexBasicLock lock(Mutex);
if (AudioThread)
{
AudioThread->join();
delete AudioThread;
AudioThread = NULL;
}
shutdownOpenALDevice();
signalEvent(ON_RELEASE);
}
@ -302,7 +292,16 @@ namespace cAudio
shutdownOpenALDevice();
signalEvent(ON_INIT);
return initOpenALDevice();
bool isInit = initOpenALDevice();
#ifdef CAUDIO_USE_INTERNAL_THREAD
if (!AudioThread)
{
AudioThread = new cAudioThread(this);
}
AudioThread->start();
#endif
return isInit;
}
bool cAudioCapture::checkError()
@ -352,16 +351,6 @@ namespace cAudio
plugins[i]->onCreateAudioCapture(capture);
}
#endif
#ifdef CAUDIO_USE_INTERNAL_THREAD
AudioCaptureObjectsMutex.lock();
AudioCaptureObjects.insert(capture);
//First time launch of thread
if(!RunAudioCaptureThread && AudioCaptureObjects.size() > 0)
RunAudioCaptureThread = (cAudioThread::SpawnThread(AudioCaptureUpdateThread, NULL) == 0);
AudioCaptureObjectsMutex.unlock();
#endif
}
return capture;
}
@ -370,16 +359,6 @@ namespace cAudio
{
if(capture)
{
#ifdef CAUDIO_USE_INTERNAL_THREAD
AudioCaptureObjectsMutex.lock();
AudioCaptureObjects.erase(capture);
//Kill the thread if there are no objects to process anymore
if(RunAudioCaptureThread && AudioCaptureObjects.empty())
RunAudioCaptureThread = false;
AudioCaptureObjectsMutex.unlock();
#endif
#ifdef CAUDIO_COMPILE_WITH_PLUGIN_SUPPORT
cAudioVector<IAudioPlugin*>::Type plugins = cPluginManager::Instance()->getPluginList();
for(unsigned int i = 0; i < plugins.size(); ++i)
@ -387,18 +366,11 @@ namespace cAudio
plugins[i]->onDestoryAudioCapture(capture);
}
#endif
CAUDIO_DELETE capture;
capture = NULL;
}
}
CAUDIO_API bool isAudioCaptureThreadRunning()
{
return RunAudioCaptureThread;
}
void cAudioCapture::registerEventHandler(ICaptureEventHandler* handler)
{
if(handler)

View File

@ -15,6 +15,7 @@
#include "../Headers/cPluginManager.h"
#include "../include/cAudioPlatform.h"
#include "../Headers/cFileSourceFactory.h"
#include "../Headers/cThread.h"
#include <string.h>
#include <algorithm>
@ -35,8 +36,6 @@
namespace cAudio
{
static bool RunAudioManagerThread(false);
#ifdef CAUDIO_COMPILE_WITH_OGG_DECODER
static cOggAudioDecoderFactory OggDecoderFactory;
#endif
@ -50,27 +49,15 @@ namespace cAudio
static cFileSourceFactory FileSourceFactory;
#endif
//Note: OpenAL is threadsafe, so a mutex only needs to protect the class state
#ifdef CAUDIO_USE_INTERNAL_THREAD
static cAudioMutex AudioManagerObjectsMutex;
static cAudioSet<IAudioManager*>::Type AudioManagerObjects;
CAUDIO_DECLARE_THREAD_FUNCTION(AudioManagerUpdateThread)
{
while(RunAudioManagerThread)
cAudioManager::~cAudioManager()
{
if (AudioThread)
{
AudioManagerObjectsMutex.lock();
cAudioSet<IAudioManager*>::Type::iterator it;
for ( it=AudioManagerObjects.begin() ; it != AudioManagerObjects.end(); it++ )
{
(*it)->update();
}
AudioManagerObjectsMutex.unlock();
cAudioSleep(1);
}
return 0;
AudioThread->join();
delete AudioThread;
AudioThread = NULL;
}
}
#endif
bool cAudioManager::initialize(const char* deviceName, int outputFrequency, int eaxEffectSlots)
{
@ -154,6 +141,13 @@ namespace cAudio
#endif
getLogger()->logInfo("AudioManager", "Supported Extensions: %s", alGetString(AL_EXTENSIONS));
#ifdef CAUDIO_USE_INTERNAL_THREAD
if (!AudioThread)
{
AudioThread = new cAudioThread(this);
}
AudioThread->start();
#endif
Initialized = true;
return true;
}
@ -723,6 +717,12 @@ namespace cAudio
return DefaultDevice.empty() ? "" : DefaultDevice.c_str();
}
void cAudioManager::run()
{
update();
cAudioSleep(1);
}
CAUDIO_API IAudioManager* createAudioManager(bool initializeDefault)
{
cAudioManager* manager = CAUDIO_NEW cAudioManager;
@ -753,19 +753,6 @@ namespace cAudio
plugins[i]->onCreateAudioManager(manager);
}
#endif
#ifdef CAUDIO_USE_INTERNAL_THREAD
AudioManagerObjectsMutex.lock();
AudioManagerObjects.insert(manager);
//First time launch of thread
if(!RunAudioManagerThread)
{
RunAudioManagerThread = true;
RunAudioManagerThread = (cAudioThread::SpawnThread(AudioManagerUpdateThread, NULL) == 0);
}
AudioManagerObjectsMutex.unlock();
#endif
}
return manager;
}
@ -774,16 +761,6 @@ namespace cAudio
{
if(manager)
{
#ifdef CAUDIO_USE_INTERNAL_THREAD
AudioManagerObjectsMutex.lock();
AudioManagerObjects.erase(manager);
//Kill the thread if there are no objects to process anymore
if(RunAudioManagerThread && AudioManagerObjects.empty())
RunAudioManagerThread = false;
AudioManagerObjectsMutex.unlock();
#endif
#ifdef CAUDIO_COMPILE_WITH_PLUGIN_SUPPORT
cAudioVector<IAudioPlugin*>::Type plugins = cPluginManager::Instance()->getPluginList();
for(unsigned int i = 0; i < plugins.size(); ++i)
@ -801,10 +778,4 @@ namespace cAudio
manager = NULL;
}
}
CAUDIO_API bool isAudioManagerThreadRunning()
{
return RunAudioManagerThread;
}
};

View File

@ -3,41 +3,94 @@
// For conditions of distribution and use, see copyright notice in cAudio.h
#include "../Headers/cThread.h"
#ifdef CAUDIO_PLATFORM_WIN
#include <windows.h> //Basic windows includes
#include <process.h>
#else
#include <pthread.h> //Assumed linux system
#endif
#include "../Include/cAudioSleep.h"
namespace cAudio
{
#ifdef CAUDIO_PLATFORM_WIN
int cAudioThread::SpawnThread( unsigned __stdcall start_address( void* ), void *arg)
{
HANDLE threadHandle;
unsigned threadID = 0;
threadHandle = (HANDLE) _beginthreadex(NULL,0,start_address,arg,0,&threadID);
int state = (threadHandle==0) ? 1 : 0;
if(state == 0)
CloseHandle( threadHandle );
return state;
}
#else
int cAudioThread::SpawnThread( void* start_address( void* ), void *arg)
{
pthread_t threadHandle;
cAudioThread::cAudioThread(IThreadWorker* pWorker) : IsInit(false), Worker(pWorker), ThreadHandle(0), Loop(true), ThreadID(0)
{
}
cAudioThread::~cAudioThread()
{
if(IsInit)
shutdown();
}
bool cAudioThread::start()
{
if(IsInit) return IsInit;
cAudioMutexBasicLock lock(Mutex);
#ifdef CAUDIO_PLATFORM_WIN
ThreadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, threadFunc, this, 0, &ThreadID));
if(ThreadHandle == 0)
CloseHandle( ThreadHandle );
#else
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
return pthread_create( &threadHandle, &attr, start_address, arg );
ThreadID = pthread_create( &ThreadHandle, &attr, threadFunc, this );
#endif
IsInit = ThreadID != 0;
return IsInit;
}
void cAudioThread::join()
{
if(IsInit)
{
cAudioMutexBasicLock lock(Mutex);
Loop = false;
#ifdef CAUDIO_PLATFORM_WIN
WaitForSingleObject(ThreadHandle, INFINITE);
#else
pthread_join(ThreadHandle, NULL);
#endif
}
}
void cAudioThread::shutdown()
{
if(IsInit)
{
cAudioMutexBasicLock lock(Mutex);
IsInit = false;
#ifdef CAUDIO_PLATFORM_WIN
_endthread();
#else
pthread_exit(0);
#endif
}
}
#endif
void cAudioThread::updateLoop()
{
if(IsInit && Worker)
{
while (Loop)
{
Worker->run();
}
}
}
bool cAudioThread::isRunning()
{
return Loop && IsInit;
}
#ifdef CAUDIO_PLATFORM_WIN
unsigned int __stdcall cAudioThread::threadFunc(void *args)
{
cAudioThread* pThread = reinterpret_cast<cAudioThread*>(args);
pThread->updateLoop();
return 0;
}
#else
void* cAudioThread::threadFunc(void* args)
{
cAudioThread* pThread = reinterpret_cast<cAudioThread*>(args);
pThread->updateLoop();
return 0;
}
#endif
};