Skip to content
Snippets Groups Projects
AUD_OpenALDevice.cpp 33.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Joerg Mueller's avatar
    Joerg Mueller committed
    /*
    
     * ***** BEGIN GPL LICENSE BLOCK *****
    
    Joerg Mueller's avatar
    Joerg Mueller committed
     *
    
     * Copyright 2009-2011 Jörg Hermann Müller
    
    Joerg Mueller's avatar
    Joerg Mueller committed
     *
     * This file is part of AudaSpace.
     *
    
     * Audaspace is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
    
    Joerg Mueller's avatar
    Joerg Mueller committed
     * (at your option) any later version.
     *
     * AudaSpace 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.  See the
    
     * GNU General Public License for more details.
    
     * You should have received a copy of the GNU General Public License
     * along with Audaspace; if not, write to the Free Software Foundation,
     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    
     * ***** END GPL LICENSE BLOCK *****
    
    /** \file audaspace/OpenAL/AUD_OpenALDevice.cpp
     *  \ingroup audopenal
     */
    
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    #include "AUD_OpenALDevice.h"
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    #include "AUD_IFactory.h"
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    #include "AUD_IReader.h"
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    #include "AUD_ConverterReader.h"
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    #include "AUD_MutexLock.h"
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    #include <cstring>
    #include <limits>
    
    #ifdef WIN32
    #include <windows.h>
    #else
    #include <unistd.h>
    #endif
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    /*struct AUD_OpenALBufferedFactory
    {
    	/// The factory.
    	AUD_IFactory* factory;
    
    	/// The OpenAL buffer.
    	ALuint buffer;
    };*/
    
    //typedef std::list<AUD_OpenALBufferedFactory*>::iterator AUD_BFIterator;
    
    
    /******************************************************************************/
    /*********************** AUD_OpenALHandle Handle Code *************************/
    /******************************************************************************/
    
    static const char* genbuffer_error = "AUD_OpenALDevice: Buffer couldn't be "
    									 "generated.";
    static const char* gensource_error = "AUD_OpenALDevice: Source couldn't be "
    									 "generated.";
    static const char* queue_error = "AUD_OpenALDevice: Buffer couldn't be "
    								 "queued to the source.";
    static const char* bufferdata_error = "AUD_OpenALDevice: Buffer couldn't be "
    									  "filled with data.";
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::pause(bool keep)
    {
    	if(m_status)
    	{
    		AUD_MutexLock lock(*m_device);
    
    		if(m_status == AUD_STATUS_PLAYING)
    		{
    			for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++)
    			{
    				if(it->get() == this)
    				{
    					boost::shared_ptr<AUD_OpenALHandle> This = *it;
    
    					m_device->m_playingSounds.erase(it);
    					m_device->m_pausedSounds.push_back(This);
    
    					alSourcePause(m_source);
    
    					m_status = keep ? AUD_STATUS_STOPPED : AUD_STATUS_PAUSED;
    
    					return true;
    				}
    			}
    		}
    	}
    
    	return false;}
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, boost::shared_ptr<AUD_IReader> reader, bool keep) :
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0),
    	m_eos(false), m_loopcount(0), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING),
    	m_device(device)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_DeviceSpecs specs = m_device->m_specs;
    	specs.specs = m_reader->getSpecs();
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	// OpenAL playback code
    	alGenBuffers(CYCLE_BUFFERS, m_buffers);
    	if(alGetError() != AL_NO_ERROR)
    		AUD_THROW(AUD_ERROR_OPENAL, genbuffer_error);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	try
    	{
    		m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
    		int length;
    		bool eos;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		for(int i = 0; i < CYCLE_BUFFERS; i++)
    		{
    			length = m_device->m_buffersize;
    			reader->read(length, eos, m_device->m_buffer.getBuffer());
    
    
    			if(length == 0)
    			{
    				// AUD_XXX: TODO: don't fill all buffers and enqueue them later
    				length = 1;
    				memset(m_device->m_buffer.getBuffer(), 0, length * AUD_DEVICE_SAMPLE_SIZE(specs));
    			}
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
    						 length * AUD_DEVICE_SAMPLE_SIZE(specs),
    						 specs.rate);
    			if(alGetError() != AL_NO_ERROR)
    				AUD_THROW(AUD_ERROR_OPENAL, bufferdata_error);
    		}
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		alGenSources(1, &m_source);
    		if(alGetError() != AL_NO_ERROR)
    			AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		try
    		{
    
    			alSourceQueueBuffers(m_source, CYCLE_BUFFERS, m_buffers);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			if(alGetError() != AL_NO_ERROR)
    				AUD_THROW(AUD_ERROR_OPENAL, queue_error);
    		}
    		catch(AUD_Exception&)
    		{
    			alDeleteSources(1, &m_source);
    			throw;
    		}
    	}
    	catch(AUD_Exception&)
    	{
    		alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
    		throw;
    	}
    	alSourcei(m_source, AL_SOURCE_RELATIVE, 1);
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::pause()
    {
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::resume()
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(m_status)
    	{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    		if(m_status == AUD_STATUS_PAUSED)
    		{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			for(AUD_HandleIterator it = m_device->m_pausedSounds.begin(); it != m_device->m_pausedSounds.end(); it++)
    			{
    				if(it->get() == this)
    				{
    					boost::shared_ptr<AUD_OpenALHandle> This = *it;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					m_device->m_pausedSounds.erase(it);
    					m_device->m_playingSounds.push_back(This);
    
    					m_device->start();
    					m_status = AUD_STATUS_PLAYING;
    
    					return true;
    				}
    			}
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		}
    	}
    
    	return false;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::stop()
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    	m_status = AUD_STATUS_INVALID;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	alDeleteSources(1, &m_source);
    	if(!m_isBuffered)
    		alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
    
    
    	for(AUD_HandleIterator it = m_device->m_playingSounds.begin(); it != m_device->m_playingSounds.end(); it++)
    	{
    		if(it->get() == this)
    		{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			boost::shared_ptr<AUD_OpenALHandle> This = *it;
    
    
    			m_device->m_playingSounds.erase(it);
    
    			return true;
    		}
    	}
    
    	for(AUD_HandleIterator it = m_device->m_pausedSounds.begin(); it != m_device->m_pausedSounds.end(); it++)
    	{
    		if(it->get() == this)
    		{
    			m_device->m_pausedSounds.erase(it);
    			return true;
    		}
    	}
    
    	return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::getKeep()
    {
    	if(m_status)
    		return m_keep;
    
    	return false;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setKeep(bool keep)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	m_keep = keep;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::seek(float position)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	if(m_isBuffered)
    		alSourcef(m_source, AL_SEC_OFFSET, position);
    	else
    	{
    		m_reader->seek((int)(position * m_reader->getSpecs().rate));
    		m_eos = false;
    
    		ALint info;
    
    		alGetSourcei(m_source, AL_SOURCE_STATE, &info);
    
    		if(info != AL_PLAYING)
    		{
    			if(info == AL_PAUSED)
    				alSourceStop(m_source);
    
    			alSourcei(m_source, AL_BUFFER, 0);
    			m_current = 0;
    
    			ALenum err;
    			if((err = alGetError()) == AL_NO_ERROR)
    			{
    				int length;
    				AUD_DeviceSpecs specs = m_device->m_specs;
    				specs.specs = m_reader->getSpecs();
    				m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
    
    				for(int i = 0; i < CYCLE_BUFFERS; i++)
    				{
    					length = m_device->m_buffersize;
    					m_reader->read(length, m_eos, m_device->m_buffer.getBuffer());
    
    
    					if(length == 0)
    					{
    						// AUD_XXX: TODO: don't fill all buffers and enqueue them later
    						length = 1;
    						memset(m_device->m_buffer.getBuffer(), 0, length * AUD_DEVICE_SAMPLE_SIZE(specs));
    					}
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
    								 length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate);
    
    					if(alGetError() != AL_NO_ERROR)
    						break;
    				}
    
    				if(m_loopcount != 0)
    					m_eos = false;
    
    				alSourceQueueBuffers(m_source, CYCLE_BUFFERS, m_buffers);
    			}
    
    			alSourceRewind(m_source);
    		}
    	}
    
    
    	if(m_status == AUD_STATUS_STOPPED)
    		m_status = AUD_STATUS_PAUSED;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getPosition()
    {
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    	if(!m_status)
    		return 0.0f;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	float position = 0.0f;
    
    	alGetSourcef(m_source, AL_SEC_OFFSET, &position);
    
    	if(!m_isBuffered)
    	{
    		AUD_Specs specs = m_reader->getSpecs();
    		position += (m_reader->getPosition() - m_device->m_buffersize *
    					 CYCLE_BUFFERS) / (float)specs.rate;
    	}
    
    	return position;
    }
    
    AUD_Status AUD_OpenALDevice::AUD_OpenALHandle::getStatus()
    {
    	return m_status;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getVolume()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_GAIN, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setVolume(float volume)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_GAIN, volume);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getPitch()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_PITCH, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setPitch(float pitch)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_PITCH, pitch);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    int AUD_OpenALDevice::AUD_OpenALHandle::getLoopCount()
    {
    	if(!m_status)
    		return 0;
    	return m_loopcount;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setLoopCount(int count)
    {
    	if(!m_status)
    		return false;
    
    
    	if(m_status == AUD_STATUS_STOPPED && (count > m_loopcount || count < 0))
    		m_status = AUD_STATUS_PAUSED;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	m_loopcount = count;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	return true;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setStopCallback(stopCallback callback, void* data)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	m_stop = callback;
    	m_stop_data = data;
    
    	return true;
    }
    
    /******************************************************************************/
    /********************* AUD_OpenALHandle 3DHandle Code *************************/
    /******************************************************************************/
    
    AUD_Vector3 AUD_OpenALDevice::AUD_OpenALHandle::getSourceLocation()
    {
    	AUD_Vector3 result = AUD_Vector3(0, 0, 0);
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	ALfloat p[3];
    	alGetSourcefv(m_source, AL_POSITION, p);
    
    	result = AUD_Vector3(p[0], p[1], p[2]);
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceLocation(const AUD_Vector3& location)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcefv(m_source, AL_POSITION, (ALfloat*)location.get());
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    AUD_Vector3 AUD_OpenALDevice::AUD_OpenALHandle::getSourceVelocity()
    {
    	AUD_Vector3 result = AUD_Vector3(0, 0, 0);
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	ALfloat v[3];
    	alGetSourcefv(m_source, AL_VELOCITY, v);
    
    	result = AUD_Vector3(v[0], v[1], v[2]);
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceVelocity(const AUD_Vector3& velocity)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcefv(m_source, AL_VELOCITY, (ALfloat*)velocity.get());
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    AUD_Quaternion AUD_OpenALDevice::AUD_OpenALHandle::getSourceOrientation()
    {
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	return m_orientation;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceOrientation(const AUD_Quaternion& orientation)
    {
    	ALfloat direction[3];
    	direction[0] = -2 * (orientation.w() * orientation.y() +
    						 orientation.x() * orientation.z());
    	direction[1] = 2 * (orientation.x() * orientation.w() -
    						orientation.z() * orientation.y());
    	direction[2] = 2 * (orientation.x() * orientation.x() +
    						orientation.y() * orientation.y()) - 1;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    	if(!m_status)
    		return false;
    
    	alSourcefv(m_source, AL_DIRECTION, direction);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	m_orientation = orientation;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	return true;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::isRelative()
    {
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	int result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcei(m_source, AL_SOURCE_RELATIVE, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setRelative(bool relative)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcei(m_source, AL_SOURCE_RELATIVE, relative);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getVolumeMaximum()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_MAX_GAIN, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setVolumeMaximum(float volume)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_MAX_GAIN, volume);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getVolumeMinimum()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_MIN_GAIN, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setVolumeMinimum(float volume)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_MIN_GAIN, volume);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getDistanceMaximum()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_MAX_DISTANCE, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setDistanceMaximum(float distance)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_MAX_DISTANCE, distance);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getDistanceReference()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setDistanceReference(float distance)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_REFERENCE_DISTANCE, distance);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getAttenuation()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setAttenuation(float factor)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_ROLLOFF_FACTOR, factor);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getConeAngleOuter()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_CONE_OUTER_ANGLE, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setConeAngleOuter(float angle)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_CONE_OUTER_ANGLE, angle);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getConeAngleInner()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_CONE_INNER_ANGLE, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setConeAngleInner(float angle)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_CONE_INNER_ANGLE, angle);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    float AUD_OpenALDevice::AUD_OpenALHandle::getConeVolumeOuter()
    {
    	float result = std::numeric_limits<float>::quiet_NaN();
    
    	if(!m_status)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return result;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alGetSourcef(m_source, AL_CONE_OUTER_GAIN, &result);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return result;
    }
    
    bool AUD_OpenALDevice::AUD_OpenALHandle::setConeVolumeOuter(float volume)
    {
    	if(!m_status)
    		return false;
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*m_device);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	if(!m_status)
    		return false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	alSourcef(m_source, AL_CONE_OUTER_GAIN, volume);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	return true;
    }
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    /******************************************************************************/
    /**************************** Threading Code **********************************/
    /******************************************************************************/
    
    
    static void *AUD_openalRunThread(void *device)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    {
    	AUD_OpenALDevice* dev = (AUD_OpenALDevice*)device;
    	dev->updateStreams();
    	return NULL;
    }
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    void AUD_OpenALDevice::start(bool join)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_MutexLock lock(*this);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	if(!m_playing)
    	{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		if(join)
    			pthread_join(m_thread, NULL);
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		pthread_attr_t attr;
    		pthread_attr_init(&attr);
    		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    
    		pthread_create(&m_thread, &attr, AUD_openalRunThread, this);
    
    		pthread_attr_destroy(&attr);
    
    		m_playing = true;
    	}
    }
    
    void AUD_OpenALDevice::updateStreams()
    {
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	boost::shared_ptr<AUD_OpenALHandle> sound;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	int length;
    
    	ALint info;
    
    	AUD_DeviceSpecs specs = m_specs;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	ALCenum cerr;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	std::list<boost::shared_ptr<AUD_OpenALHandle> > stopSounds;
    	std::list<boost::shared_ptr<AUD_OpenALHandle> > pauseSounds;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    	AUD_HandleIterator it;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    	while(1)
    	{
    		lock();
    
    		alcSuspendContext(m_context);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    		cerr = alcGetError(m_device);
    		if(cerr == ALC_NO_ERROR)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			// for all sounds
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    			for(it = m_playingSounds.begin(); it != m_playingSounds.end(); it++)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				sound = *it;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				// is it a streamed sound?
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				if(!sound->m_isBuffered)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					// check for buffer refilling
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					alGetSourcei(sound->m_source, AL_BUFFERS_PROCESSED, &info);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					if(info)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    						specs.specs = sound->m_reader->getSpecs();
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    						m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    						// for all empty buffers
    						while(info--)
    						{
    							// if there's still data to play back
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    							if(!sound->m_eos)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								// read data
    								length = m_buffersize;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer());
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								// looping necessary?
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								if(length == 0 && sound->m_loopcount)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									if(sound->m_loopcount > 0)
    										sound->m_loopcount--;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									sound->m_reader->seek(0);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    									length = m_buffersize;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer());
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								}
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								if(sound->m_loopcount != 0)
    									sound->m_eos = false;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								// read nothing?
    								if(length == 0)
    								{
    									break;
    								}
    
    
    								// unqueue buffer (warning: this might fail for slow early returning sources (none exist so far) if the buffer was not queued due to recent changes - has to be tested)
    								alSourceUnqueueBuffers(sound->m_source, 1, &sound->m_buffers[sound->m_current]);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								ALenum err;
    								if((err = alGetError()) != AL_NO_ERROR)
    								{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									sound->m_eos = true;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									break;
    								}
    
    								// fill with new data
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								alBufferData(sound->m_buffers[sound->m_current],
    											 sound->m_format,
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    											 m_buffer.getBuffer(), length *
    
    											 AUD_DEVICE_SAMPLE_SIZE(specs),
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    											 specs.rate);
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								if((err = alGetError()) != AL_NO_ERROR)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									sound->m_eos = true;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									break;
    								}
    
    								// and queue again
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								alSourceQueueBuffers(sound->m_source, 1,
    												&sound->m_buffers[sound->m_current]);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								if(alGetError() != AL_NO_ERROR)
    								{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									sound->m_eos = true;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    									break;
    								}
    
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    								sound->m_current = (sound->m_current+1) %
    												 AUD_OpenALHandle::CYCLE_BUFFERS;
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    							else
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				// check if the sound has been stopped
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				alGetSourcei(sound->m_source, AL_SOURCE_STATE, &info);
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    				if(info != AL_PLAYING)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					// if it really stopped
    
    					if(sound->m_eos && info != AL_INITIAL)
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    					{
    
    Joerg Mueller's avatar
    Joerg Mueller committed
    						if(sound->m_stop)
    							sound->m_stop(sound->m_stop_data);