123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /**
- * Copyright (c) 2006-2016 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
- #include "Pool.h"
- #include "Source.h"
- namespace love
- {
- namespace audio
- {
- namespace openal
- {
- Pool::Pool()
- : sources()
- , totalSources(0)
- {
- // Clear errors.
- alGetError();
- // Generate sources.
- for (int i = 0; i < MAX_SOURCES; i++)
- {
- alGenSources(1, &sources[i]);
- // We might hit an implementation-dependent limit on the total number
- // of sources before reaching MAX_SOURCES.
- if (alGetError() != AL_NO_ERROR)
- break;
- totalSources++;
- }
- if (totalSources < 4)
- throw love::Exception("Could not generate sources.");
- #ifdef AL_SOFT_direct_channels
- ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
- #endif
- // Make all sources available initially.
- for (int i = 0; i < totalSources; i++)
- {
- #ifdef AL_SOFT_direct_channels
- if (hasext)
- {
- // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
- alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
- }
- #endif
- available.push(sources[i]);
- }
- }
- Pool::~Pool()
- {
- stop();
- // Free all sources.
- alDeleteSources(totalSources, sources);
- }
- bool Pool::isAvailable() const
- {
- bool has = false;
- {
- thread::Lock lock(mutex);
- has = !available.empty();
- }
- return has;
- }
- bool Pool::isPlaying(Source *s)
- {
- bool p = false;
- {
- thread::Lock lock(mutex);
- p = (playing.find(s) != playing.end());
- }
- return p;
- }
- void Pool::update()
- {
- thread::Lock lock(mutex);
- std::map<Source *, ALuint>::iterator i = playing.begin();
- while (i != playing.end())
- {
- if (!i->first->update())
- {
- i->first->stopAtomic();
- i->first->release();
- available.push(i->second);
- playing.erase(i++);
- }
- else
- i++;
- }
- }
- int Pool::getSourceCount() const
- {
- return (int) playing.size();
- }
- int Pool::getMaxSources() const
- {
- return totalSources;
- }
- bool Pool::assignSource(Source *source, ALuint &out, char *wasPlaying)
- {
- out = 0;
- if (findSource(source, out))
- {
- if (wasPlaying)
- *wasPlaying = true;
- return true;
- }
- if (wasPlaying)
- *wasPlaying = false;
- if (available.empty())
- return false;
- out = available.front();
- available.pop();
- playing.insert(std::make_pair(source, out));
- source->retain();
- return true;
- }
- bool Pool::play(Source *source)
- {
- thread::Lock lock(mutex);
- ALuint out;
- char wasPlaying;
- if (!assignSource(source, out, &wasPlaying))
- return false;
- if (!wasPlaying)
- return source->playAtomic(out);
- else
- {
- source->resumeAtomic();
- return true;
- }
- }
- bool Pool::play(const std::vector<love::audio::Source*> &sources)
- {
- thread::Lock lock(mutex);
- std::vector<ALuint> ids(sources.size());
- // NOTE: not bool, because std::vector<bool> is implemented as a bitvector
- // which means no pointers can be created.
- std::vector<char> wasPlaying(sources.size());
- for (size_t i = 0; i < sources.size(); i++)
- {
- Source *source = (Source*) sources[i];
- if (!assignSource(source, ids[i], &wasPlaying[i]))
- {
- // Now we need to release the resources we had already allocated
- for (size_t j = 0; j < sources.size(); j++)
- if (!wasPlaying[j])
- release((Source*) sources[j]);
- return false;
- }
- }
- return Source::playAtomic(sources, ids, wasPlaying);
- }
- void Pool::stop()
- {
- thread::Lock lock(mutex);
- for (const auto &i : playing)
- {
- i.first->stopAtomic();
- i.first->release();
- available.push(i.second);
- }
- playing.clear();
- }
- void Pool::stop(Source *source)
- {
- thread::Lock lock(mutex);
- removeSource(source);
- }
- void Pool::stop(const std::vector<love::audio::Source*> &sources)
- {
- thread::Lock lock(mutex);
- Source::stopAtomic(sources);
- }
- std::vector<love::audio::Source*> Pool::pause()
- {
- thread::Lock lock(mutex);
- std::vector<love::audio::Source*> werePlaying;
- werePlaying.reserve(playing.size());
- for (const auto &i : playing)
- {
- if (!i.first->isPlaying())
- continue;
- werePlaying.push_back(i.first);
- i.first->pauseAtomic();
- }
- return werePlaying;
- }
- void Pool::pause(Source *source)
- {
- thread::Lock lock(mutex);
- ALuint out;
- if (findSource(source, out))
- source->pauseAtomic();
- }
- void Pool::pause(const std::vector<love::audio::Source*> &sources)
- {
- thread::Lock lock(mutex);
- Source::pauseAtomic(sources);
- }
- void Pool::release(Source *source)
- {
- ALuint s = findi(source);
- if (s != 0)
- {
- available.push(s);
- playing.erase(source);
- }
- }
- void Pool::seek(Source *source, float offset, void *unit)
- {
- thread::Lock lock(mutex);
- return source->seekAtomic(offset, unit);
- }
- float Pool::tell(Source *source, void *unit)
- {
- thread::Lock lock(mutex);
- return source->tellAtomic(unit);
- }
- double Pool::getDuration(Source *source, void *unit)
- {
- thread::Lock lock(mutex);
- return source->getDurationAtomic(unit);
- }
- bool Pool::queue(Source *source, void *data, ALsizei length)
- {
- thread::Lock lock(mutex);
- return source->queueAtomic(data, length);
- }
- ALuint Pool::findi(const Source *source) const
- {
- std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
- if (i != playing.end())
- return i->second;
- return 0;
- }
- bool Pool::findSource(Source *source, ALuint &out)
- {
- std::map<Source *, ALuint>::const_iterator i = playing.find((Source *)source);
- bool found = i != playing.end();
- if (found)
- out = i->second;
- return found;
- }
- bool Pool::removeSource(Source *source)
- {
- std::map<Source *, ALuint>::iterator i = playing.find((Source *)source);
- if (i != playing.end())
- {
- source->stopAtomic();
- available.push(i->second);
- playing.erase(i++);
- source->release();
- return true;
- }
- return false;
- }
- } // openal
- } // audio
- } // love
|