Implement async dispatcher #221

This commit is contained in:
Eduardo Bart
2013-03-04 18:56:22 -03:00
parent c452e74e0c
commit 0be7bd5360
13 changed files with 274 additions and 70 deletions

View File

@@ -31,11 +31,10 @@ SoundFile::SoundFile(const FileStreamPtr& fileStream)
SoundFilePtr SoundFile::loadSoundFile(const std::string& filename)
{
stdext::timer t;
FileStreamPtr file = g_resources.openFile(filename);
if(!file) {
g_logger.traceError(stdext::format("unable to open %s", filename));
return nullptr;
}
if(!file)
stdext::throw_exception(stdext::format("unable to open %s", filename));
// cache file buffer to avoid lags from hard drive
file->cache();
@@ -50,7 +49,7 @@ SoundFilePtr SoundFile::loadSoundFile(const std::string& filename)
if(oggSoundFile->prepareOgg())
soundFile = oggSoundFile;
} else
g_logger.error(stdext::format("unknown sound file format %s", filename));
stdext::throw_exception(stdext::format("unknown sound file format %s", filename));
return soundFile;
}

View File

@@ -30,6 +30,8 @@
#include <framework/core/clock.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/asyncdispatcher.h>
#include <thread>
SoundManager g_sounds;
@@ -57,9 +59,14 @@ void SoundManager::terminate()
{
ensureContext();
for(auto it = m_streamFiles.begin(); it != m_streamFiles.end();++it)
it->second.wait();
m_streamFiles.clear();
m_sources.clear();
m_buffers.clear();
m_channels.clear();
m_audioEnabled = false;
alcMakeContextCurrent(nullptr);
@@ -86,6 +93,23 @@ void SoundManager::poll()
lastUpdate = now;
ensureContext();
for(auto it = m_streamFiles.begin(); it != m_streamFiles.end();) {
StreamSoundSourcePtr source = it->first;
std::future<SoundFilePtr>& future = it->second;
if(std::is_ready(future)) {
SoundFilePtr sound = future.get();
if(sound)
source->setSoundFile(sound);
else
source->stop();
it = m_streamFiles.erase(it);
} else {
++it;
}
}
for(auto it = m_sources.begin(); it != m_sources.end();) {
SoundSourcePtr source = *it;
@@ -161,9 +185,8 @@ SoundSourcePtr SoundManager::play(std::string filename, float fadetime, float ga
soundSource->setRelative(true);
soundSource->setGain(gain);
if(fadetime > 0) {
if(fadetime > 0)
soundSource->setFading(StreamSoundSource::FadingOn, fadetime);
}
soundSource->play();
@@ -202,45 +225,55 @@ SoundSourcePtr SoundManager::createSoundSource(const std::string& filename)
source = SoundSourcePtr(new SoundSource);
source->setBuffer(it->second);
} else {
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
if(!soundFile)
return nullptr;
#if defined __linux && !defined OPENGL_ES
// due to OpenAL implementation bug, stereo buffers are always downmixed to mono on linux systems
// this is hack to work around the issue
// solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html
CombinedSoundSourcePtr combinedSource(new CombinedSoundSource);
StreamSoundSourcePtr streamSource;
if(soundFile->getSize() <= MAX_CACHE_SIZE) {
source = SoundSourcePtr(new SoundSource);
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
buffer->fillBuffer(soundFile);
source->setBuffer(buffer);
m_buffers[filename] = buffer;
g_logger.warning(stdext::format("uncached sound '%s' requested to be played", filename));
} else {
StreamSoundSourcePtr streamSource(new StreamSoundSource);
streamSource->setSoundFile(soundFile);
source = streamSource;
#if defined __linux && !defined OPENGL_ES
// due to OpenAL implementation bug, stereo buffers are always downmixed to mono on linux systems
// this is hack to work around the issue
// solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html
if(soundFile->getSampleFormat() == AL_FORMAT_STEREO16) {
CombinedSoundSourcePtr combinedSource(new CombinedSoundSource);
streamSource->downMix(StreamSoundSource::DownMixLeft);
streamSource->setRelative(true);
streamSource->setPosition(Point(-128, 0));
combinedSource->addSource(streamSource);
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
streamSource->setSoundFile(SoundFile::loadSoundFile(filename));
streamSource->downMix(StreamSoundSource::DownMixRight);
streamSource->setRelative(true);
streamSource->setPosition(Point(128,0));
combinedSource->addSource(streamSource);
source = combinedSource;
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
streamSource->downMix(StreamSoundSource::DownMixLeft);
streamSource->setRelative(true);
streamSource->setPosition(Point(-128, 0));
combinedSource->addSource(streamSource);
m_streamFiles[streamSource] = g_asyncDispatcher.schedule([=]() -> SoundFilePtr {
stdext::timer a;
try {
return SoundFile::loadSoundFile(filename);
} catch(std::exception& e) {
g_logger.error(e.what());
return nullptr;
}
#endif
}
});
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
streamSource->downMix(StreamSoundSource::DownMixRight);
streamSource->setRelative(true);
streamSource->setPosition(Point(128,0));
combinedSource->addSource(streamSource);
m_streamFiles[streamSource] = g_asyncDispatcher.schedule([=]() -> SoundFilePtr {
try {
return SoundFile::loadSoundFile(filename);
} catch(std::exception& e) {
g_logger.error(e.what());
return nullptr;
}
});
source = combinedSource;
#else
StreamSoundSourcePtr streamSource(new StreamSoundSource);
m_streamFiles[streamSource] = m_loadJobs [=]() -> SoundFilePtr {
try {
return SoundFile::loadSoundFile(filename);
} catch(std::exception& e) {
g_logger.error(e.what());
return nullptr;
}
});
source = streamSource;
#endif
}
} catch(std::exception& e) {
g_logger.error(stdext::format("failed to load sound source: '%s'", e.what()));

View File

@@ -57,6 +57,7 @@ private:
ALCdevice *m_device;
ALCcontext *m_context;
std::map<StreamSoundSourcePtr, std::future<SoundFilePtr>> m_streamFiles;
std::unordered_map<std::string, SoundBufferPtr> m_buffers;
std::vector<SoundSourcePtr> m_sources;
stdext::boolean<true> m_audioEnabled;

View File

@@ -25,6 +25,7 @@
#include "soundfile.h"
#include <framework/util/databuffer.h>
#include <boost/concept_check.hpp>
StreamSoundSource::StreamSoundSource()
{
@@ -41,22 +42,26 @@ StreamSoundSource::~StreamSoundSource()
void StreamSoundSource::setSoundFile(const SoundFilePtr& soundFile)
{
m_soundFile = soundFile;
if(m_waitingFile) {
m_waitingFile = false;
play();
}
}
void StreamSoundSource::play()
{
m_playing = true;
if(!m_soundFile) {
m_waitingFile = true;
return;
}
if(m_eof) {
m_soundFile->reset();
m_eof = false;
}
if(!m_soundFile) {
g_logger.error("there is not sound file to play the stream");
return;
}
queueBuffers();
SoundSource::play();
@@ -64,9 +69,13 @@ void StreamSoundSource::play()
void StreamSoundSource::stop()
{
m_playing = false;
if(m_waitingFile)
return;
SoundSource::stop();
unqueueBuffers();
m_playing = false;
}
void StreamSoundSource::queueBuffers()
@@ -91,6 +100,9 @@ void StreamSoundSource::unqueueBuffers()
void StreamSoundSource::update()
{
if(m_waitingFile)
return;
SoundSource::update();
int processed = 0;
@@ -118,6 +130,9 @@ void StreamSoundSource::update()
bool StreamSoundSource::fillBufferAndQueue(uint buffer)
{
if(m_waitingFile)
return false;
// fill buffer
static DataBuffer<char> bufferData(2*STREAM_FRAGMENT_SIZE);
ALenum format = m_soundFile->getSampleFormat();
@@ -170,15 +185,5 @@ bool StreamSoundSource::fillBufferAndQueue(uint buffer)
void StreamSoundSource::downMix(StreamSoundSource::DownMix downMix)
{
if(!m_soundFile) {
g_logger.error("down mix must be set after setting a sound file");
return;
}
if(m_soundFile->getSampleFormat() != AL_FORMAT_STEREO16) {
g_logger.error("can only downmix 16 bit stereo audio files");
return;
}
m_downMix = downMix;
}

View File

@@ -61,6 +61,7 @@ private:
stdext::boolean<false> m_looping;
stdext::boolean<false> m_playing;
stdext::boolean<false> m_eof;
stdext::boolean<false> m_waitingFile;
};
#endif