Browse Source

Add love.audio.setOutputDevice

Miku AuahDark 3 years ago
parent
commit
5e0f0dc02e

+ 5 - 0
src/modules/audio/Audio.cpp

@@ -78,6 +78,11 @@ bool Audio::setMixWithSystem(bool mix)
 #endif
 }
 
+void Audio::setOutputDevice(const char */*name*/)
+{
+	throw love::Exception("Re-setting output device is not supported.");
+}
+
 StringMap<Audio::DistanceModel, Audio::DISTANCE_MAX_ENUM>::Entry Audio::distanceModelEntries[] =
 {
 	{"none", Audio::DISTANCE_NONE},

+ 5 - 0
src/modules/audio/Audio.h

@@ -307,6 +307,11 @@ public:
 	 */
 	virtual void getOutputDevices(std::vector<std::string> &list) = 0;
 
+	/**
+	 * Set the output device to specified device name.
+	 */
+	virtual void setOutputDevice(const char *name);
+
 private:
 
 	static StringMap<DistanceModel, DISTANCE_MAX_ENUM>::Entry distanceModelEntries[];

+ 30 - 5
src/modules/audio/openal/Audio.cpp

@@ -98,7 +98,7 @@ static const char *getDeviceSpecifier(ALCdevice *device)
 #ifndef ALC_ALL_DEVICES_SPECIFIER
 	constexpr ALCenum ALC_ALL_DEVICES_SPECIFIER = 0x1013;
 #endif
-	static ALCenum deviceEnum = alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")
+	static ALCenum deviceEnum = alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") == ALC_TRUE
 		? ALC_ALL_DEVICES_SPECIFIER
 		: ALC_DEVICE_SPECIFIER;
 
@@ -112,6 +112,9 @@ Audio::Audio()
 	, poolThread(nullptr)
 	, distanceModel(DISTANCE_INVERSE_CLAMPED)
 {
+	attribs.push_back(0);
+	attribs.push_back(0);
+
 	// Before opening new device, check if recording
 	// is requested.
 	if (getRequestRecordingPermission())
@@ -134,12 +137,11 @@ Audio::Audio()
 			throw love::Exception("Could not open device.");
 
 #ifdef ALC_EXT_EFX
-		ALint attribs[4] = { ALC_MAX_AUXILIARY_SENDS, MAX_SOURCE_EFFECTS, 0, 0 };
-#else
-		ALint *attribs = nullptr;
+		attribs.insert(attribs.begin(), ALC_MAX_AUXILIARY_SENDS);
+		attribs.insert(attribs.begin() + 1, MAX_SOURCE_EFFECTS);
 #endif
 
-		context = alcCreateContext(device, attribs);
+		context = alcCreateContext(device, attribs.data());
 
 		if (context == nullptr)
 			throw love::Exception("Could not create context.");
@@ -350,6 +352,29 @@ void Audio::getOutputDevices(std::vector<std::string> &list)
 	}
 }
 
+void Audio::setOutputDevice(const char* name)
+{
+#undef ALC_SOFT_reopen_device
+#ifndef ALC_SOFT_reopen_device
+	typedef ALCboolean (ALC_APIENTRY*LPALCREOPENDEVICESOFT)(ALCdevice *device,
+		const ALCchar *deviceName, const ALCint *attribs);
+#endif
+	static LPALCREOPENDEVICESOFT alcReopenDeviceSOFT = alcIsExtensionPresent(device, "ALC_SOFT_reopen_device") == ALC_TRUE
+		? (LPALCREOPENDEVICESOFT) alcGetProcAddress(device, "alcReopenDeviceSOFT")
+		: nullptr;
+
+	if (alcReopenDeviceSOFT == nullptr)
+	{
+		// Default implementation throws exception. To make
+		// error message consistent, call the base class.
+		love::audio::Audio::setOutputDevice(name);
+		return;
+	}
+
+	if (alcReopenDeviceSOFT(device, (const ALCchar *) name, attribs.data()) == ALC_FALSE)
+		throw love::Exception("Cannot set output device: %s", alcGetString(device, alcGetError(device)));
+}
+
 void Audio::setVolume(float volume)
 {
 	alListenerf(AL_GAIN, volume);

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

@@ -129,6 +129,7 @@ public:
 
 	std::string getOutputDevice();
 	void getOutputDevices(std::vector<std::string> &list);
+	void setOutputDevice(const char *name);
 
 private:
 	void initializeEFX();
@@ -140,6 +141,7 @@ private:
 
 	// The OpenAL context.
 	ALCcontext *context;
+	std::vector<ALCint> attribs;
 
 	// The OpenAL effects
 	struct EffectMapStorage

+ 22 - 0
src/modules/audio/wrap_Audio.cpp

@@ -568,6 +568,27 @@ int w_getOutputDevices(lua_State* L)
 	return 1;
 }
 
+int w_setOutputDevice(lua_State* L)
+{
+	const char *device = luaL_optstring(L, 1, nullptr);
+
+	try
+	{
+		instance()->setOutputDevice(device);
+		luax_pushboolean(L, true);
+		return 1;
+	}
+	catch (love::Exception& e)
+	{
+		luax_pushboolean(L, false);
+		lua_pushstring(L, e.what());
+		return 2;
+	}
+
+	// To avoid compiler warning
+	return 0;
+}
+
 // List of functions to wrap.
 static const luaL_Reg functions[] =
 {
@@ -601,6 +622,7 @@ static const luaL_Reg functions[] =
 	{ "setMixWithSystem", w_setMixWithSystem },
 	{ "getOutputDevice", w_getOutputDevice },
 	{ "getOutputDevices", w_getOutputDevices },
+	{ "setOutputDevice", w_setOutputDevice },
 
 	{ 0, 0 }
 };