Add love.audio.setOutputDevice

This commit is contained in:
Miku AuahDark
2022-05-03 20:16:26 +08:00
parent 65b898903c
commit 5e0f0dc02e
5 changed files with 64 additions and 5 deletions
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 }
};