1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-05 15:40:10 +00:00

Reopen audio device on disconnect

This commit is contained in:
Evil Eye 2023-03-02 22:58:07 +01:00
parent 754dac6103
commit b762807dfb
3 changed files with 68 additions and 11 deletions

View File

@ -112,6 +112,10 @@ namespace
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
LPALEVENTCONTROLSOFT alEventControlSOFT;
LPALEVENTCALLBACKSOFT alEventCallbackSOFT;
LPALCREOPENDEVICESOFT alcReopenDeviceSOFT;
void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES& props)
{
ALint type = AL_NONE;
@ -601,17 +605,40 @@ namespace MWSound
return devlist;
}
void OpenAL_Output::eventCallback(
ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar* message, void* userParam)
{
if (eventType == AL_EVENT_TYPE_DISCONNECTED_SOFT)
static_cast<OpenAL_Output*>(userParam)->onDisconnect();
}
void OpenAL_Output::onDisconnect()
{
if (!mInitialized)
return;
const std::lock_guard<std::mutex> lock(mReopenMutex);
Log(Debug::Warning) << "Audio device disconnected, attempting to reopen...";
ALCboolean reopened = alcReopenDeviceSOFT(mDevice, mDeviceName.c_str(), mContextAttributes.data());
if (reopened == AL_FALSE && !mDeviceName.empty())
reopened = alcReopenDeviceSOFT(mDevice, nullptr, mContextAttributes.data());
if (reopened == AL_FALSE)
Log(Debug::Error) << "Failed to reopen audio device";
}
bool OpenAL_Output::init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode)
{
const std::lock_guard<std::mutex> lock(mReopenMutex);
deinit();
Log(Debug::Info) << "Initializing OpenAL...";
mDeviceName = devname;
mDevice = alcOpenDevice(devname.c_str());
if (!mDevice && !devname.empty())
{
Log(Debug::Warning) << "Failed to open \"" << devname << "\", trying default";
mDevice = alcOpenDevice(nullptr);
mDeviceName.clear();
}
if (!mDevice)
@ -636,17 +663,17 @@ namespace MWSound
ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF");
std::vector<ALCint> attrs;
attrs.reserve(15);
mContextAttributes.clear();
mContextAttributes.reserve(15);
if (ALC.SOFT_HRTF)
{
LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT");
attrs.push_back(ALC_HRTF_SOFT);
attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE
: hrtfmode == HrtfMode::Enable ? ALC_TRUE
:
mContextAttributes.push_back(ALC_HRTF_SOFT);
mContextAttributes.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE
: hrtfmode == HrtfMode::Enable ? ALC_TRUE
:
/*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT);
if (!hrtfname.empty())
{
@ -667,14 +694,14 @@ namespace MWSound
Log(Debug::Warning) << "Failed to find HRTF \"" << hrtfname << "\", using default";
else
{
attrs.push_back(ALC_HRTF_ID_SOFT);
attrs.push_back(index);
mContextAttributes.push_back(ALC_HRTF_ID_SOFT);
mContextAttributes.push_back(index);
}
}
}
attrs.push_back(0);
mContextAttributes.push_back(0);
mContext = alcCreateContext(mDevice, attrs.data());
mContext = alcCreateContext(mDevice, mContextAttributes.data());
if (!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE)
{
Log(Debug::Error) << "Failed to setup audio context: " << alcGetString(mDevice, alcGetError(mDevice));
@ -691,6 +718,22 @@ namespace MWSound
<< " Version: " << alGetString(AL_VERSION) << "\n"
<< " Extensions: " << alGetString(AL_EXTENSIONS);
if (alIsExtensionPresent("AL_SOFT_events"))
{
getALFunc(alEventControlSOFT, "alEventControlSOFT");
getALFunc(alEventCallbackSOFT, "alEventCallbackSOFT");
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_reopen_device"))
getALFunc(alcReopenDeviceSOFT, "alcReopenDeviceSOFT");
}
if (alEventControlSOFT)
{
static const std::array<ALenum, 1> events{ { AL_EVENT_TYPE_DISCONNECTED_SOFT } };
alEventControlSOFT(events.size(), events.data(), AL_TRUE);
alEventCallbackSOFT(&OpenAL_Output::eventCallback, this);
}
else
Log(Debug::Warning) << "Cannot detect audio device changes";
if (!ALC.SOFT_HRTF)
Log(Debug::Warning) << "HRTF status unavailable";
else
@ -867,6 +910,9 @@ namespace MWSound
alDeleteFilters(1, &mWaterFilter);
mWaterFilter = 0;
if (alEventCallbackSOFT)
alEventCallbackSOFT(nullptr, nullptr);
alcMakeContextCurrent(nullptr);
if (mContext)
alcDestroyContext(mContext);
@ -1526,6 +1572,7 @@ namespace MWSound
OpenAL_Output::~OpenAL_Output()
{
const std::lock_guard<std::mutex> lock(mReopenMutex);
OpenAL_Output::deinit();
}

View File

@ -3,6 +3,7 @@
#include <deque>
#include <map>
#include <mutex>
#include <string>
#include <vector>
@ -53,6 +54,10 @@ namespace MWSound
struct StreamThread;
std::unique_ptr<StreamThread> mStreamThread;
std::string mDeviceName;
std::vector<ALCint> mContextAttributes;
std::mutex mReopenMutex;
void initCommon2D(ALuint source, const osg::Vec3f& pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv);
void initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, ALfloat gain,
ALfloat pitch, bool loop, bool useenv);
@ -65,6 +70,11 @@ namespace MWSound
OpenAL_Output& operator=(const OpenAL_Output& rhs);
OpenAL_Output(const OpenAL_Output& rhs);
static void eventCallback(
ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar* message, void* userParam);
void onDisconnect();
public:
std::vector<std::string> enumerate() override;
bool init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode) override;

View File

@ -79,7 +79,7 @@ namespace MWSound
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound)
: mVFS(vfs)
, mOutput(new OpenAL_Output(*this))
, mOutput(std::make_unique<OpenAL_Output>(*this))
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
, mSoundBuffers(*vfs, *mOutput)
, mListenerUnderwater(false)