From 65b898903c6c688d0f971d1235bfcd02a2f8f18e Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Tue, 3 May 2022 19:29:24 +0800 Subject: [PATCH] Add love.audio.getOutputDevice(s). --- src/modules/audio/Audio.h | 10 +++++++++ src/modules/audio/null/Audio.cpp | 9 ++++++++ src/modules/audio/null/Audio.h | 3 +++ src/modules/audio/openal/Audio.cpp | 36 ++++++++++++++++++++++++++++++ src/modules/audio/openal/Audio.h | 3 +++ src/modules/audio/wrap_Audio.cpp | 27 ++++++++++++++++++++++ 6 files changed, 88 insertions(+) diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index 8a4ae8bcf..cd617514b 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -297,6 +297,16 @@ public: virtual void pauseContext() = 0; virtual void resumeContext() = 0; + /** + * Get current output device name. + */ + virtual std::string getOutputDevice() = 0; + + /** + * Retrieve list of available output devices. + */ + virtual void getOutputDevices(std::vector &list) = 0; + private: static StringMap::Entry distanceModelEntries[]; diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 588f651ce..70babb0f7 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -211,6 +211,15 @@ void Audio::resumeContext() { } +std::string Audio::getOutputDevice() +{ + return ""; +} + +void Audio::getOutputDevices(std::vector &/*list*/) +{ +} + } // null } // audio diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 062bb9999..11689d151 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -89,6 +89,9 @@ public: void pauseContext(); void resumeContext(); + std::string getOutputDevice(); + void getOutputDevices(std::vector &list); + private: float volume; DistanceModel distanceModel; diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 68645e351..655c063a7 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -93,6 +93,18 @@ ALenum Audio::getFormat(int bitDepth, int channels) return AL_NONE; } +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") + ? ALC_ALL_DEVICES_SPECIFIER + : ALC_DEVICE_SPECIFIER; + + return alcGetString(device, deviceEnum); +} + Audio::Audio() : device(nullptr) , context(nullptr) @@ -314,6 +326,30 @@ void Audio::resumeContext() alcMakeContextCurrent(context); } +std::string Audio::getOutputDevice() +{ + const char *dev = getDeviceSpecifier(device); + + if (dev == nullptr) + throw Exception("Failed to get current device: %s", alcGetString(device, alcGetError(device))); + + return dev; +} + +void Audio::getOutputDevices(std::vector &list) +{ + const char *devices = getDeviceSpecifier(nullptr); + + if (devices == nullptr) + throw Exception("Failed to enumerate devices: %s", alcGetString(nullptr, alcGetError(nullptr))); + + for (const char *device = devices; *device; device++) + { + list.emplace_back(device); + device += list.back().length(); + } +} + void Audio::setVolume(float volume) { alListenerf(AL_GAIN, volume); diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 02b8a5f51..58af10987 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -127,6 +127,9 @@ public: bool getEffectID(const char *name, ALuint &id); + std::string getOutputDevice(); + void getOutputDevices(std::vector &list); + private: void initializeEFX(); // The OpenAL device. diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index 21c8429e3..3ef9ab884 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -543,6 +543,31 @@ int w_setMixWithSystem(lua_State *L) return 1; } +int w_getOutputDevice(lua_State* L) +{ + std::string device; + + luax_catchexcept(L, [&]() { device = instance()->getOutputDevice(); }); + luax_pushstring(L, device); + return 1; +} + +int w_getOutputDevices(lua_State* L) +{ + std::vector list; + + luax_catchexcept(L, [&]() { instance()->getOutputDevices(list); }); + lua_createtable(L, 0, (int) list.size()); + for (int i = 0; i < (int) list.size(); i++) + { + lua_pushnumber(L, i + 1); + lua_pushstring(L, list[i].c_str()); + lua_rawset(L, -3); + } + + return 1; +} + // List of functions to wrap. static const luaL_Reg functions[] = { @@ -574,6 +599,8 @@ static const luaL_Reg functions[] = { "getMaxSourceEffects", w_getMaxSourceEffects }, { "isEffectsSupported", w_isEffectsSupported }, { "setMixWithSystem", w_setMixWithSystem }, + { "getOutputDevice", w_getOutputDevice }, + { "getOutputDevices", w_getOutputDevices }, { 0, 0 } };