diff options
Diffstat (limited to 'src/uscxml/plugins/invoker/audio/OpenALPlayer.cpp')
-rw-r--r-- | src/uscxml/plugins/invoker/audio/OpenALPlayer.cpp | 541 |
1 files changed, 0 insertions, 541 deletions
diff --git a/src/uscxml/plugins/invoker/audio/OpenALPlayer.cpp b/src/uscxml/plugins/invoker/audio/OpenALPlayer.cpp deleted file mode 100644 index 3aaeddf..0000000 --- a/src/uscxml/plugins/invoker/audio/OpenALPlayer.cpp +++ /dev/null @@ -1,541 +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 - */ - -#include "OpenALPlayer.h" -#include <assert.h> -#include <stdexcept> - -tthread::recursive_mutex OpenALPlayer::_alMutex; - -/** -* Create a new OpenAL stream source -*/ -OpenALPlayer::OpenALPlayer(ALCcontext* context, OpenALPlayerCallback* audioCallback, ALenum format, ALsizei freq) { - - _isInitialized = false; - _audioCallback = audioCallback; - _freq = freq; - _format = format; - _bufferSize = 0; - _nrBuffers = 0; - _thread = NULL; - _alId = 0; - - _position[0] = _position[1] = _position[2] = 0; - _velocity[0] = _velocity[1] = _velocity[2] = 0; - _direction[0] = _direction[1] = _direction[2] = 0; - - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - if (context == NULL) { - // this is in essence alutInit() from freealut. - - // use the current context if there is one - _context = alcGetCurrentContext(); - - if (_context == NULL) { -// std::cout << "\tnew context" << std::endl; - // create a new context if none was given and no is current - - // get default device - ALCdevice* device = alcOpenDevice(NULL); - if (device == NULL) { - throw std::runtime_error("__FILE__ __LINE__ openal error opening device"); - } - - // create new context with device - _context = alcCreateContext (device, NULL); - if (_context == NULL) { - alcCloseDevice (device); - throw std::runtime_error("openal error create context"); - } - - // make context current - if (!alcMakeContextCurrent (_context)) { - alcDestroyContext (_context); - alcCloseDevice (device); - throw std::runtime_error("openal error make context current"); - } - } else { -// std::cout << "\texisting context" << std::endl; - } - } else { -// std::cout << "\tgiven context" << std::endl; - _context = context; - } -} - -OpenALPlayer::~OpenALPlayer() { - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - if (isPlaying()) { - alSourceStop(_alId); - } - if (_thread) { - stop(); - _thread->join(); - delete(_thread); - } - - if (_isInitialized) { - alDeleteSources(1, &_alId); - if (alIsSource(_alId)) { - throw std::runtime_error("openal source id still valid"); - } - for (size_t i = 0; i < _nrBuffers; i++) { - assert(alIsBuffer(_bufferIds[i])); - free(_buffers[i]); - } - alDeleteBuffers(_nrBuffers, _bufferIds); - for (size_t i = 0; i < _nrBuffers; i++) { -// assert(!alIsBuffer(_bufferIds[i])); - } - free(_buffers); - free(_bufferIds); - } - // clear errors and begone - alGetError(); - -} - -/** -* Allocate; data and set defaults -*/ -void OpenALPlayer::init() { - _userData = NULL; - _pitch = 0; - _gain = 0; - _referenceDistance = 1.0; - _isLooping = false; - - // no one set a buffer size yet - if (_bufferSize <= 0) - _bufferSize = ALPLAY_AUDIO_BUFFER_SIZE; - - // no one set the number of buffers yet - if (_nrBuffers <= 0) - _nrBuffers = ALPLAY_NR_AUDIO_BUFFERS; - - _isInitialized = true; - - _buffers = (char**)malloc(_nrBuffers * sizeof(char*)); - _bufferIds = (ALuint*)malloc(_nrBuffers * sizeof(ALuint)); - for (size_t i = 0; i < _nrBuffers; i++) { - _buffers[i] = 0; //(char*)malloc(_bufferSize); - } - - // there are other formats as well and this will have to be extended - int bytesPerSample = 2; - switch(_format) { - case AL_FORMAT_MONO8: - case AL_FORMAT_STEREO8: - bytesPerSample = 1; - break; - - case AL_FORMAT_MONO16: - case AL_FORMAT_STEREO16: - bytesPerSample = 2; - break; - } - - // how many ms audio is in one buffer? - _msForBuffer = (int)(((float)_bufferSize / (float)bytesPerSample) / ((float)_freq / 1000.0f)); - _initialSleep = (_msForBuffer - (int)(0.6 * _msForBuffer)) * _nrBuffers; - _bufferSleep = _msForBuffer - (int)(0.4 * _msForBuffer); - _repollSleep = _msForBuffer - (int)(0.7 * _msForBuffer); - -// std::cout << _msForBuffer << "ms in one buffer" << std::endl; - - // get available buffer ids - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - - if (!alcMakeContextCurrent (_context)) { - throw std::runtime_error("openal error make context current"); - } - - alGenBuffers(_nrBuffers, _bufferIds); - checkOpenALError(__LINE__); - - // get new source id from openAL - alGenSources(1, &_alId); - - checkOpenALError(__LINE__); - if (!alIsSource(_alId)) { - throw std::runtime_error("openal source id not valid"); - } - - // set our position and various flags to meaningful defaults - alSourcei (_alId, AL_SOURCE_RELATIVE, AL_TRUE); - checkOpenALError(__LINE__); - alSourcei(_alId, AL_LOOPING, AL_FALSE); - checkOpenALError(__LINE__); - alSourcefv(_alId, AL_POSITION, _position); - checkOpenALError(__LINE__); -// alSourcef(_alId,AL_REFERENCE_DISTANCE, 5.0f); -// checkOpenALError(__LINE__); - alDistanceModel(AL_LINEAR_DISTANCE); - checkOpenALError(__LINE__); - alSourcefv(_alId, AL_VELOCITY, _velocity); - checkOpenALError(__LINE__); - alSourcefv(_alId, AL_DIRECTION, _direction); - checkOpenALError(__LINE__); -// alSourcef (_alId, AL_ROLLOFF_FACTOR, 1.0); -// checkOpenALError(__LINE__); -// alSourcef(_alId,AL_REFERENCE_DISTANCE, 5.0f); -// checkOpenALError(__LINE__); -// float listener[] = { 0.0, 0.0, 0.0 }; -// alListenerfv(AL_POSITION, listener); -// checkOpenALError(__LINE__); -} - -/** -* Start the sound source. -* -* This will trigger continuous calls top the audio callback. -*/ -void OpenALPlayer::start() { - if (!_isInitialized) - init(); - - if (_audioCallback == NULL) - throw std::runtime_error("cannot start without an audio callback"); - - _isStarted = true; - - // prime the buffers with some initial data and register for buffer ids - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - for (ALuint i = 0; i < (unsigned int)_nrBuffers; i++) { - _buffers[i] = (char*)malloc(_bufferSize); - _audioCallback->getSamples(_buffers[i], _bufferSize, this); - alBufferData(_bufferIds[i], _format, _buffers[i], _bufferSize, _freq); - checkOpenALError(__LINE__); - } - // enqueue all buffers - alSourceQueueBuffers(_alId, _nrBuffers, _bufferIds); - checkOpenALError(__LINE__); - - // start thread - if (_audioCallback != NULL) { - _thread = new tthread::thread(&OpenALPlayer::updateBuffersWrapper, this); - } - - // tell openAL to start rendering the buffers - alSourcePlay(_alId); - checkOpenALError(__LINE__); -} - -// find bufferId in _bufferIds to get bufferIndex into _buffers - messy -int OpenALPlayer::bufferIndex(int bufferId) { - int bufferIndex = 0; - for (; bufferIndex < _nrBuffers; bufferIndex++) { - if (_bufferIds[bufferIndex] == (unsigned int)bufferId) - break; - } - if (bufferIndex >= _nrBuffers) - throw std::runtime_error("could not find dequeued bufferId in ids"); - return bufferIndex; -} - -/** -* Write a buffer (blocking). -* -* This allows for a pushing model, whereas the callback allows for a polling model. -*/ -int OpenALPlayer::write(char* buffer, int size, int* repollAt, bool blocking) { - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - - if (!_isInitialized) - init(); - - if (_audioCallback != NULL) { - throw std::runtime_error("you cannot use the write interface with an audio callback"); - } - - if (size != _bufferSize) { - throw std::runtime_error("buffersize does not match"); - } - - if (!alcMakeContextCurrent (_context)) { - throw std::runtime_error("openal error make context current"); - } - - // try to enqueue the given buffer data - for (;;) { - // do we have an empty buffer in the OpenAL queue? - int processed; - alGetSourcei(_alId, AL_BUFFERS_PROCESSED, &processed); - checkOpenALError(__LINE__); - -// if (!isPlaying()) -// std::cout << "-"; - - if (processed > 0) { -// std::cout << "P" << processed; - ALuint bufferId = 0; - alSourceUnqueueBuffers(_alId, 1, &bufferId); - checkOpenALError(__LINE__); - - int bufferIdx = bufferIndex(bufferId); - - // fill the buffer with the given data - memcpy(_buffers[bufferIdx], buffer, _bufferSize); - alBufferData(bufferId, _format, _buffers[bufferIdx], _bufferSize, _freq); - checkOpenALError(__LINE__); - - // enqueue - alSourceQueueBuffers(_alId, 1, &bufferId); - checkOpenALError(__LINE__); - - // some buffers were processed - if (repollAt) - *repollAt = _repollSleep; - break; - - } else { - // no buffer processed - is there an uninitialized buffer left? - int nextBuffer = 0; - for(; nextBuffer < _nrBuffers; nextBuffer++) { - if (_buffers[nextBuffer] == 0) { - break; - } - } - if (nextBuffer < _nrBuffers) { -// std::cout << "N"; - _buffers[nextBuffer] = (char*)malloc(_bufferSize); - memcpy(_buffers[nextBuffer], buffer, _bufferSize); - - alBufferData(_bufferIds[nextBuffer], _format, _buffers[nextBuffer], _bufferSize, _freq); - checkOpenALError(__LINE__); - - alSourceQueueBuffers(_alId, 1, &_bufferIds[nextBuffer]); - checkOpenALError(__LINE__); - // there was a free buffer, repoll immediately to try to write more - if (repollAt) - *repollAt = 0; - - break; - } else { -// std::cout << "X"; - // no processed, no new buffer, wait until we processed one - if (blocking) { - tthread::this_thread::sleep_for(tthread::chrono::milliseconds(_repollSleep)); - } else { - if (repollAt) - *repollAt = _repollSleep; - return -1; - } - } - } - } - - // we have at least one buffer queued, start playing - if (!_isStarted || !isPlaying()) { - alSourcePlay(_alId); - checkOpenALError(__LINE__); - _isStarted = true; - } - - return size; -} - - -/** -* Dequeue, refill and re-enqueue buffers. -*/ -void OpenALPlayer::updateBuffers() { - int processed; -// int queued; - -// std::cout << "Initial sleep: " << initialSleep << "ms" << std::endl; -// std::cout << "Buffer sleep: " << bufferSleep << "ms" << std::endl; -// std::cout << "Repoll sleep: " << repollSleep << "ms" << std::endl; - tthread::this_thread::sleep_for(tthread::chrono::milliseconds(_bufferSleep * _initialSleep)); - - - while(_isStarted) { - - // how many buffers have been rendered already? - tthread::lock_guard<tthread::recursive_mutex> lock(_alMutex); - alGetSourcei(_alId, AL_BUFFERS_PROCESSED, &processed); - checkOpenALError(__LINE__); - //std::cout << processed << std::flush; - - if (processed == 0) { - // avoid busy wait by sleeping - tthread::this_thread::sleep_for(tthread::chrono::milliseconds(_bufferSleep * _initialSleep)); - } else { - // dequeue buffers and get ids - // see http://stackoverflow.com/questions/1900665/c-compiler-differences-vs2008-and-g - ALuint bufferIds[ALPLAY_NR_AUDIO_BUFFERS]; - alSourceUnqueueBuffers(_alId, processed, bufferIds); - checkOpenALError(__LINE__); - - for (size_t id = 0; id < processed; id++) { - int bufferIdx = bufferIndex(bufferIds[id]); - - // refill the buffer with data from the callback - _audioCallback->getSamples(_buffers[bufferIdx], _bufferSize, this); - alBufferData(bufferIds[id], _format, _buffers[bufferIdx], _bufferSize, _freq); - checkOpenALError(__LINE__); - - } - // re-enqueue - alSourceQueueBuffers(_alId, processed, bufferIds); - checkOpenALError(__LINE__); - - // restart if we are not running anymore - if (!isPlaying()) { - alSourcePlay(_alId); - checkOpenALError(__LINE__); - } - - // sleep a bit less than the duration of one buffer - tthread::this_thread::sleep_for(tthread::chrono::milliseconds(_bufferSleep * processed)); - } - } -} - -/** -* TODO -*/ -void OpenALPlayer::stop() { - _isStarted = false; - _thread->join(); -} - -void OpenALPlayer::checkOpenALError(int line) { - int error = alGetError(); - if(error != AL_NO_ERROR) { - std::stringstream out; - out << "OpenALError:" << line << ":"; - - switch (error) { - case AL_INVALID_NAME: - out << "OpenAL invalid name."; - break; - case AL_INVALID_ENUM: - out << "OpenAL invalid enum."; - break; - case AL_INVALID_VALUE: - out << "OpenAL invalid value."; - break; - case AL_INVALID_OPERATION: - out << "OpenAL invalid operation."; - break; - case AL_OUT_OF_MEMORY: - out << "OpenAL out of memory."; - break; - - default: - out << "OpenAL unknown error."; - break; - } - throw std::runtime_error(out.str()); - } -} - -unsigned int OpenALPlayer::isPlaying() { - ALint val; - alGetSourcei(_alId, AL_SOURCE_STATE, &val); - if(val != AL_PLAYING) - return 0; - return _repollSleep; -} - -void OpenALPlayer::updateBuffersWrapper(void *obj) { - try { - reinterpret_cast<OpenALPlayer *>(obj)->updateBuffers(); - } catch(std::runtime_error& error) { -// std::cout << "Terminating Thread: " << error << std::endl; - } catch(...) { -// std::cout << "Terminating Thread! " << std::endl; - } -} - -void OpenALPlayer::setNrBuffers(int nrBuffers) { - if (_nrBuffers > 0) - throw std::runtime_error("cannot modify number of buffers"); - _nrBuffers = nrBuffers; -} - -int OpenALPlayer::getNrBuffers() { - return _nrBuffers; -} - -/** -* Set position of sound source in coordinate system -*/ -void OpenALPlayer::setPosition(ALfloat position[]) { - memcpy(&_position, position, 3 * sizeof(ALfloat)); -// std::cout << _position[0] << ", " << _position[1] << ", " << _position[2] << std::endl; - if (_isInitialized) - alSourcefv(_alId, AL_POSITION, _position); -} - -ALfloat* OpenALPlayer::getPosition() { - return _position; -} - -/** -* Set velocity of sound source in coordinate system -*/ -void OpenALPlayer::setVelocity(ALfloat velocity[]) { - memcpy(&_velocity, velocity, 3 * sizeof(ALfloat)); - if (_isInitialized) - alSourcefv(_alId, AL_VELOCITY, _velocity); -} - -ALfloat* OpenALPlayer::getVelocity() { - return _velocity; -} - -/** -* Set direction of sound source in coordinate system -*/ -void OpenALPlayer::setDirection(ALfloat direction[]) { - memcpy(&_direction, direction, 3 * sizeof(ALfloat)); - if (_isInitialized) - alSourcefv(_alId, AL_DIRECTION, _direction); -} - -ALfloat* OpenALPlayer::getDirection() { - return _direction; -} - -void OpenALPlayer::setBufferSize(int bufferSize) { - if (_bufferSize > 0) - throw std::runtime_error("cannot modify buffersize"); - _bufferSize = bufferSize; -} - -int OpenALPlayer::getBufferSize() { - return _bufferSize; -} - -OpenALPlayerCallback* OpenALPlayer::getCallback() { - return _audioCallback; -} -void OpenALPlayer::setCallback(OpenALPlayerCallback* callback) { - _audioCallback = callback; -} - -void* OpenALPlayer::getUserData() { - return _userData; -} -void OpenALPlayer::setUserData(void* userData) { - _userData = userData; -} |