Browse Source

Increased robustness of audio module initialization (see issue #646.) Also changed Source:play to return a boolean indicating success.

Alex Szpakowski 11 years ago
parent
commit
a49c2a88c1

+ 1 - 1
src/modules/audio/Audio.h

@@ -88,7 +88,7 @@ public:
 	 * Play the specified Source.
 	 * @param source The Source to play.
 	 **/
-	virtual void play(Source *source) = 0;
+	virtual bool play(Source *source) = 0;
 
 	/**
 	 * Stops playback on the specified source.

+ 1 - 1
src/modules/audio/Source.h

@@ -53,7 +53,7 @@ public:
 
 	virtual Source *clone() = 0;
 
-	virtual void play() = 0;
+	virtual bool play() = 0;
 	virtual void stop() = 0;
 	virtual void pause() = 0;
 	virtual void resume() = 0;

+ 2 - 5
src/modules/audio/null/Audio.cpp

@@ -61,12 +61,9 @@ int Audio::getMaxSources() const
 	return 0;
 }
 
-void Audio::play(love::audio::Source *)
-{
-}
-
-void Audio::play()
+bool Audio::play(love::audio::Source *)
 {
+	return false;
 }
 
 void Audio::stop(love::audio::Source *)

+ 1 - 2
src/modules/audio/null/Audio.h

@@ -48,8 +48,7 @@ public:
 	love::audio::Source *newSource(love::sound::SoundData *soundData);
 	int getSourceCount() const;
 	int getMaxSources() const;
-	void play(love::audio::Source *source);
-	void play();
+	bool play(love::audio::Source *source);
 	void stop(love::audio::Source *source);
 	void stop();
 	void pause(love::audio::Source *source);

+ 2 - 1
src/modules/audio/null/Source.cpp

@@ -42,8 +42,9 @@ love::audio::Source *Source::clone()
 	return this;
 }
 
-void Source::play()
+bool Source::play()
 {
+	return false;
 }
 
 void Source::stop()

+ 1 - 1
src/modules/audio/null/Source.h

@@ -39,7 +39,7 @@ public:
 	virtual ~Source();
 
 	virtual love::audio::Source *clone();
-	virtual void play();
+	virtual bool play();
 	virtual void stop();
 	virtual void pause();
 	virtual void resume();

+ 28 - 14
src/modules/audio/openal/Audio.cpp

@@ -69,22 +69,25 @@ void Audio::PoolThread::setFinish()
 }
 
 Audio::Audio()
-	: distanceModel(DISTANCE_INVERSE_CLAMPED)
+	: device(nullptr)
+	, capture(nullptr)
+	, context(nullptr)
+	, pool(nullptr)
+	, poolThread(nullptr)
+	, distanceModel(DISTANCE_INVERSE_CLAMPED)
 {
-	// Passing zero for default device.
-	device = alcOpenDevice(0);
+	// Passing null for default device.
+	device = alcOpenDevice(nullptr);
 
-	if (device == 0)
+	if (device == nullptr)
 		throw love::Exception("Could not open device.");
 
-	context = alcCreateContext(device, 0);
+	context = alcCreateContext(device, nullptr);
 
-	if (context == 0)
+	if (context == nullptr)
 		throw love::Exception("Could not create context.");
 
-	alcMakeContextCurrent(context);
-
-	if (alcGetError(device) != ALC_NO_ERROR)
+	if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
 		throw love::Exception("Could not make context current.");
 
 	/*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
@@ -108,7 +111,18 @@ Audio::Audio()
 	}*/
 
 	// pool must be allocated after AL context.
-	pool = new Pool();
+	try
+	{
+		pool = new Pool();
+	}
+	catch (love::Exception &)
+	{
+		alcMakeContextCurrent(nullptr);
+		alcDestroyContext(context);
+		//if (capture) alcCaptureCloseDevice(capture);
+		alcCloseDevice(device);
+		throw;
+	}
 
 	poolThread = new PoolThread(pool);
 	poolThread->start();
@@ -122,7 +136,7 @@ Audio::~Audio()
 	delete poolThread;
 	delete pool;
 
-	alcMakeContextCurrent(0);
+	alcMakeContextCurrent(nullptr);
 	alcDestroyContext(context);
 	//if (capture) alcCaptureCloseDevice(capture);
 	alcCloseDevice(device);
@@ -154,9 +168,9 @@ int Audio::getMaxSources() const
 	return pool->getMaxSources();
 }
 
-void Audio::play(love::audio::Source *source)
+bool Audio::play(love::audio::Source *source)
 {
-	source->play();
+	return source->play();
 }
 
 void Audio::stop(love::audio::Source *source)
@@ -281,7 +295,7 @@ bool Audio::canRecord()
 
 Audio::DistanceModel Audio::getDistanceModel() const
 {
-	return this->distanceModel;
+	return distanceModel;
 }
 
 void Audio::setDistanceModel(DistanceModel distanceModel)

+ 1 - 2
src/modules/audio/openal/Audio.h

@@ -67,8 +67,7 @@ public:
 	love::audio::Source *newSource(love::sound::SoundData *soundData);
 	int getSourceCount() const;
 	int getMaxSources() const;
-	void play(love::audio::Source *source);
-	void play();
+	bool play(love::audio::Source *source);
 	void stop(love::audio::Source *source);
 	void stop();
 	void pause(love::audio::Source *source);

+ 30 - 10
src/modules/audio/openal/Pool.cpp

@@ -30,23 +30,43 @@ namespace openal
 {
 
 Pool::Pool()
+	: sources()
+	, totalSources(0)
+	, mutex(nullptr)
 {
+	// Clear errors.
+	alGetError();
+
 	// Generate sources.
-	alGenSources(NUM_SOURCES, 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.");
 
 	// Create the mutex.
 	mutex = thread::newMutex();
 
-	if (alGetError() != AL_NO_ERROR)
-		throw love::Exception("Could not generate sources.");
+	ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
 
 	// Make all sources available initially.
-	for (int i = 0; i < NUM_SOURCES; i++)
+	for (int i = 0; i < totalSources; i++)
 	{
-#ifdef AL_DIRECT_CHANNELS_SOFT
-		// Bypassing virtualization of speakers for multi-channel sources in OpenAL Soft.
-		alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
-#endif
+		if (hasext)
+		{
+			// Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
+			alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
+		}
+
 		available.push(sources[i]);
 	}
 }
@@ -58,7 +78,7 @@ Pool::~Pool()
 	delete mutex;
 
 	// Free all sources.
-	alDeleteSources(NUM_SOURCES, sources);
+	alDeleteSources(totalSources, sources);
 }
 
 bool Pool::isAvailable() const
@@ -113,7 +133,7 @@ int Pool::getSourceCount() const
 
 int Pool::getMaxSources() const
 {
-	return NUM_SOURCES;
+	return totalSources;
 }
 
 bool Pool::play(Source *source, ALuint &out)

+ 8 - 3
src/modules/audio/openal/Pool.h

@@ -36,6 +36,7 @@
 #ifdef LOVE_MACOSX_USE_FRAMEWORKS
 #include <OpenAL-Soft/alc.h>
 #include <OpenAL-Soft/al.h>
+#include <OpenAL-Soft/alext.h>
 #else
 #include <AL/alc.h>
 #include <AL/al.h>
@@ -99,11 +100,15 @@ private:
 
 	bool findSource(Source *source, ALuint &out);
 	bool removeSource(Source *source);
-	// Number of OpenAL sources.
-	static const int NUM_SOURCES = 64;
+
+	// Maximum possible number of OpenAL sources the pool attempts to generate.
+	static const int MAX_SOURCES = 64;
 
 	// OpenAL sources
-	ALuint sources[NUM_SOURCES];
+	ALuint sources[MAX_SOURCES];
+
+	// Total number of created sources in the pool.
+	int totalSources;
 
 	// A queue of available sources.
 	std::queue<ALuint> available;

+ 3 - 2
src/modules/audio/openal/Source.cpp

@@ -165,15 +165,16 @@ love::audio::Source *Source::clone()
 	return new Source(*this);
 }
 
-void Source::play()
+bool Source::play()
 {
 	if (valid && paused)
 	{
 		pool->resume(this);
-		return;
+		return true;
 	}
 
 	valid = pool->play(this, source);
+	return valid;
 }
 
 void Source::stop()

+ 1 - 1
src/modules/audio/openal/Source.h

@@ -76,7 +76,7 @@ public:
 	virtual ~Source();
 
 	virtual love::audio::Source *clone();
-	virtual void play();
+	virtual bool play();
 	virtual void stop();
 	virtual void pause();
 	virtual void resume();

+ 2 - 2
src/modules/audio/wrap_Audio.cpp

@@ -75,8 +75,8 @@ int w_newSource(lua_State *L)
 int w_play(lua_State *L)
 {
 	Source *s = luax_checksource(L, 1);
-	instance->play(s);
-	return 0;
+	luax_pushboolean(L, instance->play(s));
+	return 1;
 }
 
 int w_stop(lua_State *L)

+ 2 - 2
src/modules/audio/wrap_Source.cpp

@@ -44,8 +44,8 @@ int w_Source_clone(lua_State *L)
 int w_Source_play(lua_State *L)
 {
 	Source *t = luax_checksource(L, 1);
-	t->play();
-	return 0;
+	luax_pushboolean(L, t->play());
+	return 1;
 }
 
 int w_Source_stop(lua_State *L)