caudio/cAudio/src/cAudioManager.cpp

733 lines
19 KiB
C++

// Copyright (c) 2008-2011 Raynaldo (Wildicv) Rivera, Joshua (Dark_Kilauea) Jones, Murat (wolfmanfx) Sari
// This file is part of the "cAudio Engine"
// For conditions of distribution and use, see copyright notice in cAudio.h
#include "cAudioManager.h"
#include "cAudio.h"
#include "cAudioSource.h"
#include "cAudioStaticSource.h"
#include "cAudioPlatform.h"
#include "cAudioSleep.h"
#include "cUtils.h"
#include "cThread.h"
#include "cLogger.h"
#include "cPluginManager.h"
#include "cThread.h"
#include "cMemorySource.h"
#include "cRawAudioDecoderFactory.h"
#include <string.h>
#include <algorithm>
#include "cOpenALDeviceContext.h"
namespace cAudio
{
cAudioManager::~cAudioManager()
{
cAudioManager::shutDown();
}
bool cAudioManager::initialize(const char* deviceName, int outputFrequency, int eaxEffectSlots)
{
cAudioMutexBasicLock lock(Mutex);
if(Initialized)
return false;
AudioContext = CAUDIO_NEW cOpenALDeviceContext(this);
if(!AudioContext->initialize(deviceName, outputFrequency, eaxEffectSlots))
return false;
#ifdef CAUDIO_USE_INTERNAL_THREAD
if (!AudioThread)
{
AudioThread = new cAudioThread(this);
}
AudioThread->start();
#endif
Initialized = true;
return true;
}
void cAudioManager::shutDown()
{
if(Initialized)
{
if (AudioThread) // First wait for our update thread to finish up
{
AudioThread->join();
delete AudioThread;
AudioThread = NULL;
}
cAudioMutexBasicLock lock(Mutex);
unRegisterAllAudioDecoders();
unRegisterAllDataSources();
unRegisterAllEventHandlers();
releaseAllSources();
if (AudioContext)
{
AudioContext->shutDown();
CAUDIO_DELETE AudioContext;
AudioContext = NULL;
}
Initialized = false;
getLogger()->logInfo("AudioManager", "Manager successfully shutdown.");
}
}
void cAudioManager::update()
{
updateSources.clear();
{
cAudioMutexBasicLock lock(Mutex);
size_t count = audioSources.size();
for(size_t i=0; i<count; i++)
{
IAudioSource* source = audioSources[i];
if (source->isValid())
{
source->grab();
updateSources.push_back(source);
}
}
}
// not holding the mutex because this might take a while!
for (int i=0; i != updateSources.size(); i++)
{
IAudioSource *src = updateSources[i];
src->update();
src->drop();
}
cAudioMutexBasicLock lock(Mutex);
if (!managedAudioSources.empty())
{
size_t count = managedAudioSources.size();
for(size_t i=0; i<count; i++)
{
IAudioSource* source = managedAudioSources[i];
if (source->isValid())
{
source->update();
if (source->isStopped())
{
managedAudioSourcesDelBuffer.push_back(source);
}
}
}
count = managedAudioSourcesDelBuffer.size();
for(size_t i=0; i<count; i++)
{
IAudioSource* source = managedAudioSourcesDelBuffer[i];
cAudioVector<IAudioSource*>::Type::iterator it = std::find(managedAudioSources.begin(), managedAudioSources.end(), source);
if (it != managedAudioSources.end())
{
managedAudioSources.erase(it);
CAUDIO_DELETE source;
}
}
managedAudioSourcesDelBuffer.clear();
}
signalEvent(ON_UPDATE);
}
void cAudioManager::run()
{
if(!audioSources.empty())
update();
cAudioSleep(1);
}
bool cAudioManager::isUpdateThreadRunning()
{
return (AudioThread != NULL && AudioThread->isRunning());
}
#if CAUDIO_EFX_ENABLED == 1
IAudioEffects* cAudioManager::getEffects()
{
if (AudioContext)
{
return AudioContext->getEffects();
}
return NULL;
}
#endif
IAudioSource* cAudioManager::play2D(const char* filename, bool playLooped, bool startPaused)
{
cAudioMutexBasicLock lock(Mutex);
IAudioSource* pAudioSrc = create("", filename, true);
if (!pAudioSrc)
return NULL;
if (!playLooped && !startPaused)
{
cAudioVector<IAudioSource*>::Type::iterator it = std::find(audioSources.begin(), audioSources.end(), pAudioSrc);
if (it != audioSources.end())
{
audioSources.erase(it);
}
managedAudioSources.push_back(pAudioSrc);
pAudioSrc->play2d();
return NULL;
}
if (playLooped && !startPaused)
{
pAudioSrc->play2d(true);
}
return pAudioSrc;
}
IAudioSource* cAudioManager::play3D(const char* filename, cVector3 position, bool playLooped, bool startPaused)
{
cAudioMutexBasicLock lock(Mutex);
IAudioSource* pAudioSrc = create("", filename, true);
if (!playLooped && !startPaused)
{
cAudioVector<IAudioSource*>::Type::iterator it = std::find(audioSources.begin(), audioSources.end(), pAudioSrc);
if (it != audioSources.end())
{
audioSources.erase(it);
}
managedAudioSources.push_back(pAudioSrc);
pAudioSrc->play3d(position);
return NULL;
}
if (playLooped && !startPaused)
{
pAudioSrc->play3d(position, 1.0, true);
}
return pAudioSrc;
}
void cAudioManager::setMasterVolume(float vol)
{
cAudioMutexBasicLock lock(Mutex);
MasterVolume = vol;
size_t count = audioSources.size();
for(size_t i=0; i<count; i++)
{
audioSources[i]->setVolume(audioSources[i]->getVolume());
}
}
float cAudioManager::getMasterVolume() const
{
return MasterVolume;
}
void cAudioManager::setSpeedOfSound(float speed)
{
alSpeedOfSound(speed);
checkALError();
}
float cAudioManager::getSpeedOfSound() const
{
return alGetFloat(AL_SPEED_OF_SOUND);
}
void cAudioManager::setDopplerFactor(float factor) const
{
alDopplerFactor(factor);
checkALError();
}
float cAudioManager::getDopplerFactor() const
{
return alGetFloat(AL_DOPPLER_FACTOR);
}
void cAudioManager::stopAllSounds()
{
cAudioMutexBasicLock lock(Mutex);
size_t count = audioSources.size();
for(size_t i=0; i<count; i++)
{
if(audioSources[i]->isPlaying())
audioSources[i]->stop();
}
}
IAudioSource* cAudioManager::createAudioSource(IAudioDecoder* decoder, const cAudioString& audioName, const cAudioString& dataSource)
{
if (!decoder)
return NULL;
if(decoder->isValid())
{
#if CAUDIO_EFX_ENABLED == 1
IAudioSource* audio = CAUDIO_NEW cAudioSource(decoder, AudioContext, ((cAudioEffects*)getEffects())->getEFXInterface());
#else
IAudioSource* audio = CAUDIO_NEW cAudioSource(decoder, AudioContext);
#endif
decoder->drop();
if(audio && audio->isValid())
{
if(!audioName.empty())
audioIndex[audioName] = audio;
audioSources.push_back(audio);
getLogger()->logInfo("AudioManager", "Audio Source (%s) created from Data Source %s.", toUTF8(audioName), toUTF8(dataSource));
return audio;
}
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Error creating audio source.", toUTF8(audioName));
audio->drop();
return NULL;
}
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Audio data could not be decoded by (.%s) decoder.",
toUTF8(audioName), toUTF8(decoder->getType()));
decoder->drop();
return NULL;
}
IAudioSource* cAudioManager::create(const char* name, const char* filename, bool stream)
{
if(!Initialized) return NULL;
cAudioMutexBasicLock lock(Mutex);
cAudioString audioName = fromUTF8(name);
cAudioString path = fromUTF8(filename);
cAudioString ext = getExt(path);
IAudioDecoderFactory* factory = getAudioDecoderFactory(toUTF8(ext));
if(!factory) {
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): No decoder could be found for (.%s).", toUTF8(audioName), toUTF8(ext));
return NULL;
}
for(size_t i=0; i<dataSourcePriorityList.size(); ++i)
{
const cAudioString dataSourceName = dataSourcePriorityList[i].second;
IDataSourceFactory* dataFactory = datasourcemap[dataSourceName];
if(dataFactory)
{
IDataSource* source = dataFactory->CreateDataSource(filename, stream);
if(source && source->isValid())
{
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
source->drop();
IAudioSource* audio = createAudioSource(decoder, audioName, dataSourceName);
if(audio != NULL)
return audio;
return NULL;
}
}
}
return NULL;
}
IAudioSource* cAudioManager::createFromMemory(const char* name, const char* data, size_t length, const char* extension)
{
if(!Initialized) return NULL;
cAudioMutexBasicLock lock(Mutex);
cAudioString audioName = fromUTF8(name);
cAudioString ext = fromUTF8(extension);
IAudioDecoderFactory* factory = getAudioDecoderFactory(toUTF8(ext));
if(!factory) {
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Codec (.%s) is not supported.", toUTF8(audioName), toUTF8(ext));
return NULL;
}
cMemorySource* source = CAUDIO_NEW cMemorySource(data, length, true);
if(source && source->isValid())
{
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
source->drop();
IAudioSource* audio = createAudioSource(decoder, audioName, _CTEXT("cMemorySource"));
if(audio != NULL)
return audio;
}
return NULL;
}
IAudioSource* cAudioManager::createFromAudioBuffer(const char* name, AudioCaptureBuffer* pBiffer, unsigned int frequency, AudioFormats format)
{
return createFromRaw(name, pBiffer->getWriteBuffer(), pBiffer->getLength(), frequency, format);
}
IAudioSource* cAudioManager::createFromRaw(const char* name, const char* data, size_t length, unsigned int frequency, AudioFormats format)
{
if(!Initialized) return NULL;
cAudioMutexBasicLock lock(Mutex);
cAudioString audioName = fromUTF8(name);
IAudioDecoderFactory* factory = getAudioDecoderFactory("raw");
if(!factory) {
getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): Codec (.raw) is not supported.", toUTF8(audioName));
return NULL;
}
cMemorySource* source = CAUDIO_NEW cMemorySource(data, length, true);
if(source && source->isValid())
{
IAudioDecoder* decoder = ((cRawAudioDecoderFactory*)factory)->CreateAudioDecoder(source, frequency, format);
source->drop();
IAudioSource* audio = createAudioSource(decoder, audioName, _CTEXT("cMemorySource"));
if(audio != NULL)
return audio;
}
return NULL;
}
IAudioBuffer* cAudioManager::createBuffer(const char* filename)
{
if(!Initialized) return NULL;
cAudioMutexBasicLock lock(Mutex);
cAudioString path = fromUTF8(filename);
cAudioString ext = getExt(path);
IAudioDecoderFactory* factory = getAudioDecoderFactory(toUTF8(ext));
if(!factory) {
getLogger()->logError("AudioManager", "Failed to create Audio Buffer: No decoder could be found for (.%s).", toUTF8(ext));
return NULL;
}
for(size_t i=0; i<dataSourcePriorityList.size(); ++i)
{
const cAudioString dataSourceName = dataSourcePriorityList[i].second;
IDataSourceFactory* dataFactory = datasourcemap[dataSourceName];
if(dataFactory)
{
IDataSource* source = dataFactory->CreateDataSource(filename, false);
if(source && source->isValid())
{
IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
source->drop();
IAudioBuffer* buffer = CAUDIO_NEW cAudioBuffer(decoder);
if(buffer != NULL)
return buffer;
return NULL;
}
}
}
return NULL;
}
IAudioSource* cAudioManager::createStatic(IAudioBuffer* buffer)
{
if(!Initialized) return NULL;
// FIXME save a reference?
IAudioSource *audio = CAUDIO_NEW cAudioStaticSource(buffer, AudioContext);
return audio;
}
bool cAudioManager::registerAudioDecoder(IAudioDecoderFactory* factory, const char* extension)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString ext = fromUTF8(extension);
decodermap[ext] = factory;
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s registered.", toUTF8(ext));
return true;
}
void cAudioManager::unRegisterAudioDecoder(const char* extension)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString ext = fromUTF8(extension);
decodermapIterator it = decodermap.find(ext);
if(it != decodermap.end())
{
decodermap.erase(it);
getLogger()->logInfo("AudioManager", "Audio Decoder for extension .%s unregistered.", toUTF8(ext));
}
}
bool cAudioManager::isAudioDecoderRegistered(const char* extension)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString ext = fromUTF8(extension);
decodermapIterator it = decodermap.find(ext);
return (it != decodermap.end());
}
IAudioDecoderFactory* cAudioManager::getAudioDecoderFactory(const char* extension)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString ext = fromUTF8(extension);
decodermapIterator it = decodermap.find(ext);
if(it != decodermap.end())
{
return it->second;
}
return NULL;
}
void cAudioManager::unRegisterAllAudioDecoders()
{
cAudioMutexBasicLock lock(Mutex);
decodermap.clear();
}
bool compareDataSourcePriorities(std::pair<int, cAudioString> left, std::pair<int, cAudioString> right)
{
return (left.first > right.first);
}
bool cAudioManager::registerDataSource(IDataSourceFactory* factory, const char* name, int priority)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString safeName = fromUTF8(name);
datasourcemap[safeName] = factory;
dataSourcePriorityList.push_back(std::pair<int, cAudioString>(priority, safeName));
std::sort(dataSourcePriorityList.begin(), dataSourcePriorityList.end(), compareDataSourcePriorities);
getLogger()->logInfo("AudioManager", "Data Source named %s registered (Priority %i).", toUTF8(safeName), priority);
return true;
}
void cAudioManager::unRegisterDataSource(const char* name)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString safeName = fromUTF8(name);
datasourcemapIterator it = datasourcemap.find(safeName);
if(it != datasourcemap.end())
{
datasourcemap.erase(it);
getLogger()->logInfo("AudioManager", "Data Source named %s unregistered.", toUTF8(safeName));
}
for(size_t i=0; i<dataSourcePriorityList.size(); ++i)
{
if(dataSourcePriorityList[i].second == safeName)
{
dataSourcePriorityList.erase(dataSourcePriorityList.begin()+i);
break;
}
}
std::sort(dataSourcePriorityList.begin(), dataSourcePriorityList.end(), compareDataSourcePriorities);
}
bool cAudioManager::isDataSourceRegistered(const char* name)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString safeName = fromUTF8(name);
datasourcemapIterator it = datasourcemap.find(safeName);
return (it != datasourcemap.end());
}
IDataSourceFactory* cAudioManager::getDataSourceFactory(const char* name)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString safeName = fromUTF8(name);
datasourcemapIterator it = datasourcemap.find(safeName);
if(it != datasourcemap.end())
{
return it->second;
}
return NULL;
}
void cAudioManager::unRegisterAllDataSources()
{
cAudioMutexBasicLock lock(Mutex);
datasourcemap.clear();
dataSourcePriorityList.clear();
}
void cAudioManager::registerEventHandler(IManagerEventHandler* handler)
{
if(handler)
{
eventHandlerList.push_back(handler);
}
}
void cAudioManager::unRegisterEventHandler(IManagerEventHandler* handler)
{
if(handler)
{
eventHandlerList.remove(handler);
}
}
void cAudioManager::unRegisterAllEventHandlers()
{
eventHandlerList.clear();
}
void cAudioManager::signalEvent(Events sevent)
{
cAudioMutexBasicLock lock(Mutex);
cAudioList<IManagerEventHandler*>::Type::iterator it = eventHandlerList.begin();
if(it != eventHandlerList.end())
{
switch(sevent)
{
case ON_INIT:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onInit();
}
break;
case ON_UPDATE:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onUpdate();
}
break;
case ON_RELEASE:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onRelease();
}
break;
case ON_SOURCECREATE:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onSourceCreate();
}
break;
case ON_DECODERREGISTER:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onDecoderRegister();
}
break;
case ON_DATASOURCEREGISTER:
for(; it != eventHandlerList.end(); it++)
{
(*it)->onDataSourceRegister();
}
break;
}
}
}
IAudioSource* cAudioManager::getSoundByName(const char* name)
{
cAudioMutexBasicLock lock(Mutex);
cAudioString audioName = fromUTF8(name);
audioIndexIterator i = audioIndex.find(audioName);
if (i == audioIndex.end())
{
return NULL;
}
return i->second;
}
void cAudioManager::releaseAllSources()
{
cAudioMutexBasicLock lock(Mutex);
cAudioVector<IAudioSource*>::Type::iterator audioSourcesIter;
cAudioVector<IAudioSource*>::Type deleteSources;
for(audioSourcesIter = audioSources.begin(); audioSourcesIter != audioSources.end(); ++audioSourcesIter)
{
if((*audioSourcesIter))
deleteSources.push_back(*audioSourcesIter);
}
for(audioSourcesIter = deleteSources.begin(); audioSourcesIter != deleteSources.end(); ++audioSourcesIter)
(*audioSourcesIter)->drop();
deleteSources.clear();
audioSources.clear();
audioIndex.clear();
cAudioVector<IAudioSource*>::Type::iterator managedAudioIter;
for(managedAudioIter = managedAudioSources.begin(); managedAudioIter != managedAudioSources.end(); managedAudioIter++)
{
if ((*managedAudioIter))
{
CAUDIO_DELETE (*managedAudioIter);
}
}
managedAudioSources.clear();
cAudioVector<IAudioSource*>::Type::iterator managedAudioSourcesDelIter;
for(managedAudioSourcesDelIter = managedAudioSourcesDelBuffer.begin(); managedAudioSourcesDelIter != managedAudioSourcesDelBuffer.end(); managedAudioSourcesDelIter++)
{
if ((*managedAudioSourcesDelIter))
{
CAUDIO_DELETE (*managedAudioSourcesDelIter);
}
}
managedAudioSourcesDelBuffer.clear();
}
void cAudioManager::release(IAudioSource* source)
{
if(source)
{
cAudioMutexBasicLock lock(Mutex);
audioIndexIterator it = audioIndex.begin();
for ( it=audioIndex.begin(); it != audioIndex.end(); it++ )
{
if( it->second == source )
{
audioIndex.erase(it);
break;
}
}
for(unsigned int i=0; i<audioSources.size(); ++i)
{
if(source == audioSources[i])
{
audioSources.erase(audioSources.begin()+i);
if (source->getReferenceCount() <= 1)
CAUDIO_DELETE source;
else
source->drop();
break;
}
}
}
}
};