diff options
Diffstat (limited to 'src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp')
-rw-r--r-- | src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp | 421 |
1 files changed, 0 insertions, 421 deletions
diff --git a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp b/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp deleted file mode 100644 index e813f2f..0000000 --- a/src/uscxml/plugins/invoker/audio/OpenALInvoker.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/** - * @file - * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) - * @copyright Simplified BSD - * - * @cond - * This program is free software: you can redistribute it and/or modify - * it under the terms of the FreeBSD license as published by the FreeBSD - * project. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the FreeBSD license along with this - * program. If not, see <http://www.opensource.org/licenses/bsd-license>. - * @endcond - */ - -// see http://stackoverflow.com/questions/6563810/m-pi-works-with-math-h-but-not-with-cmath-in-visual-studio -#define _USE_MATH_DEFINES -#include <cmath> - -#include <boost/algorithm/string.hpp> - -#include "OpenALInvoker.h" -#include <uscxml/config.h> -#include <glog/logging.h> -#include <limits.h> - -#ifdef BUILD_AS_PLUGINS -#include <Pluma/Connector.hpp> -#endif - -namespace uscxml { - -#ifdef BUILD_AS_PLUGINS -PLUMA_CONNECTOR -bool pluginConnect(pluma::Host& host) { - host.add( new OpenALInvokerProvider() ); - return true; -} -#endif - -// see http://stackoverflow.com/questions/1904635/warning-c4003-and-errors-c2589-and-c2059-on-x-stdnumeric-limitsintmax -#undef max - -OpenALInvoker::OpenALInvoker() { - _isStarted = false; - _alContext = NULL; - _alDevice = NULL; - _thread = NULL; - _listenerPos[0] = _listenerPos[1] = _listenerPos[2] = 0; - _listenerVel[0] = _listenerVel[1] = _listenerVel[2] = 0; - _maxPos[0] = _maxPos[1] = _maxPos[2] = 1; - - _listenerOrient[0] = _listenerOrient[1] = _listenerOrient[3] = _listenerOrient[5] = 0; - _listenerOrient[2] = _listenerOrient[4] = 1.0; -} - -OpenALInvoker::~OpenALInvoker() { - if (_thread) { - _isStarted = false; - _sourcesAvailable.notify_all(); - _thread->join(); - delete(_thread); - } - if (_alContext) { -// alcCloseDevice(alcGetContextsDevice(_alContext)); -// alcDestroyContext(_alContext); - } -}; - -boost::shared_ptr<InvokerImpl> OpenALInvoker::create(InterpreterImpl* interpreter) { - boost::shared_ptr<OpenALInvoker> invoker = boost::shared_ptr<OpenALInvoker>(new OpenALInvoker()); - invoker->_interpreter = interpreter; - return invoker; -} - -Data OpenALInvoker::getDataModelVariables() { - Data data; - return data; -} - -void OpenALInvoker::send(const SendRequest& req) { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - - if (!_isStarted) - start(); - - if (iequals(req.name, "play")) { - if (req.params.find("src") == req.params.end()) { - LOG(ERROR) << "Sent event play with no src URL"; - } - - URL srcURL = req.params.find("src")->second.atom; - if (!srcURL.toAbsolute(_interpreter->getBaseURL(req.elem))) { - LOG(ERROR) << "src URL " << req.params.find("src")->second << " is relative with no base URI set for interpreter"; - return; - } - - _sources[req.sendid] = new OpenALSource(); - _sources[req.sendid]->loop = req.params.find("loop") != req.params.end() && iequals(req.params.find("loop")->second.atom, "true"); - _sources[req.sendid]->file = srcURL; -#ifdef LIBSNDFILE_FOUND - _sources[req.sendid]->transform = new LibSoundFile(srcURL.asLocalFile(".audio")); -#else -# ifdef AUDIOTOOLBOX_FOUND - _sources[req.sendid]->transform = new AudioToolbox(srcURL.asLocalFile(".audio")); -# endif -#endif - if (_sources[req.sendid]->transform == NULL) { - LOG(ERROR) << "No transcoder for input file known - install libsndfile or AudioToolbox"; - _sources.erase(req.sendid); - return; - } - - // force mono format to ensure actual spatial audio - PCMFormat format = _sources[req.sendid]->transform->getInFormat(); - format.alFormat = AL_FORMAT_MONO16; - _sources[req.sendid]->transform->setOutFormat(format); - - try { - _sources[req.sendid]->player = new OpenALPlayer(_alContext, NULL, format.alFormat, format.sampleRate); - } catch (std::exception ex) { - returnErrorExecution(ex.what()); - return; - } - - getPosFromParams(req.params, _sources[req.sendid]->pos); - - _sources[req.sendid]->pos[0] -= _listenerPos[0]; - _sources[req.sendid]->pos[1] -= _listenerPos[1]; - _sources[req.sendid]->pos[2] -= _listenerPos[2]; - try { - _sources[req.sendid]->player->setPosition(_sources[req.sendid]->pos); - - } catch (std::exception ex) { - returnErrorExecution(ex.what()); - } - - _sourcesAvailable.notify_all(); - } - - if (iequals(req.name, "move.source")) { - std::string sourceId; - if (req.params.find("source") == req.params.end()) { - LOG(WARNING) << "Cannot move source with no source given in parameters"; - return; - } - sourceId = req.params.find("source")->second.atom; - - if (_sources.find(sourceId) == _sources.end()) { - LOG(WARNING) << "Given source '" << sourceId << "' not active or not existing"; - return; - } - - getPosFromParams(req.params, _sources[sourceId]->pos); - try { - _sources[sourceId]->player->setPosition(_sources[sourceId]->pos); - } catch (std::exception ex) { - returnErrorExecution(ex.what()); - } - } - - if (iequals(req.name, "move.listener")) { - getPosFromParams(req.params, _listenerPos); - - try { - alcMakeContextCurrent(_alContext); - alListenerfv(AL_POSITION, _listenerPos); - OpenALPlayer::checkOpenALError(__LINE__); - } catch (std::exception ex) { - returnErrorExecution(ex.what()); - } - } - -} - -void OpenALInvoker::start() { - _isStarted = true; - _thread = new tthread::thread(&OpenALInvoker::fillBuffers, this); -} - -void OpenALInvoker::fillBuffers(void* userdata) { - OpenALInvoker* INST = (OpenALInvoker*)userdata; - while(INST->_isStarted) { - // do nothing until we have at least one source - int waitMs = std::numeric_limits<int>::max(); - INST->_mutex.lock(); - while (INST->_sources.size() == 0 && INST->_isStarted) { - INST->_sourcesAvailable.wait(INST->_mutex); - } - - if (!INST->_isStarted) - return; - - // here we are with at least one source and a locked mutex - assert(INST->_sources.size() > 0); - - std::map<std::string, OpenALSource*>::iterator srcIter = INST->_sources.begin(); - while(srcIter != INST->_sources.end()) { - OpenALSource* src = srcIter->second; - int wait = std::numeric_limits<int>::max(); - - if (src->finished) { - // source has already finished playing, feed no more samples to it - try { - wait = src->player->isPlaying(); - if (wait == 0) { - // source stopped playing, delete it - INST->notifyOfEnd(src); - delete src; - INST->_sources.erase(srcIter++); - continue; - } else { - // source returned time when to repoll - assert(wait > 0); - } - } catch (std::exception ex) { - INST->returnErrorExecution(ex.what()); - delete src; - INST->_sources.erase(srcIter++); - continue; - } - } else { - // source still needs more samples or play existing buffer - if (src->written == src->read) { - // all read samples have been written, read some more - src->written = 0; - src->read = src->transform->read(src->buffer, ALPLAY_AUDIO_BUFFER_SIZE); - if (src->read < ALPLAY_AUDIO_BUFFER_SIZE) { - if (src->loop) { - INST->notifyOfLoop(src); - while (src->read < ALPLAY_AUDIO_BUFFER_SIZE) { - src->transform->seek(0); - src->read += src->transform->read(src->buffer + src->read, ALPLAY_AUDIO_BUFFER_SIZE - src->read); - } - } else { - src->finished = true; - memset(src->buffer + src->read, 0, ALPLAY_AUDIO_BUFFER_SIZE - src->read); - } - } - } - - // there are unwritten samples in the buffer - if (src->read != src->written) { - try { - int written = src->player->write(src->buffer, ALPLAY_AUDIO_BUFFER_SIZE, &wait); - if (written >=0 ) { - src->written += written; - } - } catch (std::exception ex) { - INST->returnErrorExecution(ex.what()); - src->finished = true; - } - } else { - assert(src->finished); - } - } - - waitMs = (wait < waitMs ? wait : waitMs); - srcIter++; - } - -// std::cout << "W" << waitMs << "."; - - INST->_mutex.unlock(); - if (waitMs < std::numeric_limits<int>::max()) - tthread::this_thread::sleep_for(tthread::chrono::milliseconds(waitMs)); - } -} - -void OpenALInvoker::cancel(const std::string sendId) { - tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); - -} - -void OpenALInvoker::invoke(const InvokeRequest& req) { - _alDevice = alcOpenDevice(NULL); - if (_alDevice == NULL) { - throw std::string("__FILE__ __LINE__ openal error opening device"); - } - - std::multimap<std::string, Data>::const_iterator paramIter = req.params.begin(); - while(paramIter != req.params.end()) { - if (iequals(paramIter->first, "maxX")) - _maxPos[0] = strTo<float>(paramIter->second.atom); - if (iequals(paramIter->first, "maxY")) - _maxPos[1] = strTo<float>(paramIter->second.atom); - if (iequals(paramIter->first, "maxZ")) - _maxPos[2] = strTo<float>(paramIter->second.atom); - paramIter++; - } - - // create new context with device - _alContext = alcCreateContext (_alDevice, NULL); - if (_alContext == NULL) { - alcCloseDevice (_alDevice); - throw std::string("openal error create context"); - } - -// std::cout << boost::lexical_cast<std::string>(_alContext); -// std::cout << boost::lexical_cast<std::string>(_alDevice); - - alcMakeContextCurrent(_alContext); -// float listener[3] = {0,0,0}; -// alListenerfv(AL_POSITION, listener); - - alcMakeContextCurrent(_alContext); - alListenerfv(AL_POSITION, _listenerPos); - alListenerfv(AL_VELOCITY, _listenerVel); - alListenerfv(AL_ORIENTATION, _listenerOrient); - - alListenerf(AL_GAIN, 0.5); - - start(); -} - -void OpenALInvoker::notifyOfEnd(OpenALSource* src) { - Event ev; - ev.name = "audio.end"; - ev.data.compound["file"] = src->file; - returnEvent(ev); -} - -void OpenALInvoker::notifyOfLoop(OpenALSource* src) { - Event ev; - ev.name = "audio.loop"; - ev.data.compound["file"] = src->file; - returnEvent(ev); -} - -void OpenALInvoker::getPosFromParams(const std::multimap<std::string, Data>& params, float* position) { - // vector explicitly given - try { - if (params.find("x") != params.end()) - position[0] = boost::lexical_cast<float>(params.find("x")->second); - if (params.find("y") != params.end()) - position[1] = boost::lexical_cast<float>(params.find("y")->second); - if (params.find("z") != params.end()) - position[2] = boost::lexical_cast<float>(params.find("z")->second); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret x, y or z as float value in params: " << e.what(); - } - - try { - // right is an alias for x - if (params.find("right") != params.end()) - position[0] = boost::lexical_cast<float>(params.find("right")->second); - // height is an alias for y - if (params.find("height") != params.end()) - position[1] = boost::lexical_cast<float>(params.find("height")->second); - // front is an alias for z - if (params.find("front") != params.end()) - position[2] = boost::lexical_cast<float>(params.find("front")->second); - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret right, height or front as float value in params: " << e.what(); - } - - // do we have a position on a circle? - try { - if (params.find("circle") != params.end()) { - float rad = posToRadian(params.find("circle")->second); - position[0] = cosf(rad); - position[2] = -1 * sinf(rad); // z axis increases to front -// position[0] *= 150; -// position[2] *= 150; - - } - } catch (boost::bad_lexical_cast& e) { - LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); - } - - position[0] = position[0] / _maxPos[0]; - position[1] = position[1] / _maxPos[1]; - position[2] = position[2] / _maxPos[2]; -// std::cout << position[0] << ":" << position[1] << ":" << position[2] << std::endl; - -} - -float OpenALInvoker::posToRadian(const std::string& pos) { - - std::string trimmedPos = boost::trim_copy(pos); - float rad = 0; - - if (trimmedPos.size() > 3 && iequals("deg", trimmedPos.substr(trimmedPos.length() - 3, 3))) { - rad = boost::lexical_cast<float>(trimmedPos.substr(0, trimmedPos.size() - 3)); - rad = fmodf(rad, 360); // into range [0-360] - rad /= 180; // into range [0-2] - rad *= M_PI; // into range [0-2PI] - rad -= M_PI_2; // 0 to top; - rad *= -1; // make clockwise - rad += 2 * M_PI; // make positive - } else if (trimmedPos.size() > 3 && iequals("rad", trimmedPos.substr(trimmedPos.length() - 3, 3))) { - rad = boost::lexical_cast<float>(trimmedPos.substr(0, trimmedPos.size() - 3)); - rad = fmodf(rad, M_PI * 2); // into range [0-2*PI] - } else { - LOG(ERROR) << "Cannot make sense of position value " << trimmedPos << ": does not end in 'deg', 'rad'"; - } - return rad; -} - -OpenALSource::OpenALSource() { - pos[0] = pos[1] = pos[2] = 0; - player = NULL; - loop = false; - finished = false; - transform = NULL; - read = written = 0; - memset(buffer, 0, ALPLAY_AUDIO_BUFFER_SIZE); -} - -OpenALSource::~OpenALSource() { - if (player) - delete player; - if (transform) - delete transform; -} - -}
\ No newline at end of file |