mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:29:55 +00:00
Switch to new default device if default device changes
This commit is contained in:
parent
b762807dfb
commit
e020af8b4a
3 changed files with 100 additions and 14 deletions
|
@ -5,6 +5,7 @@
|
|||
Bug #3842: Body part skeletons override the main skeleton
|
||||
Bug #4127: Weapon animation looks choppy
|
||||
Bug #4204: Dead slaughterfish doesn't float to water surface after loading saved game
|
||||
Bug #4382: Sound output device does not change when it should
|
||||
Bug #4610: Casting a Bound Weapon spell cancels the casting animation by equipping the weapon prematurely
|
||||
Bug #4816: GetWeaponDrawn returns 1 before weapon is attached
|
||||
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
@ -165,6 +166,17 @@ namespace
|
|||
getALError();
|
||||
}
|
||||
|
||||
std::basic_string_view<ALCchar> getDeviceName(ALCdevice* device)
|
||||
{
|
||||
const ALCchar* name = nullptr;
|
||||
if (alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT"))
|
||||
name = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
|
||||
if (alcGetError(device) != AL_NO_ERROR || !name)
|
||||
name = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||
if (name == nullptr) // Prevent assigning nullptr to std::string
|
||||
return {};
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
|
@ -314,8 +326,7 @@ namespace MWSound
|
|||
//
|
||||
struct OpenAL_Output::StreamThread
|
||||
{
|
||||
typedef std::vector<OpenAL_SoundStream*> StreamVec;
|
||||
StreamVec mStreams;
|
||||
std::vector<OpenAL_SoundStream*> mStreams;
|
||||
|
||||
std::atomic<bool> mQuitNow;
|
||||
std::mutex mMutex;
|
||||
|
@ -342,7 +353,7 @@ namespace MWSound
|
|||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
while (!mQuitNow)
|
||||
{
|
||||
StreamVec::iterator iter = mStreams.begin();
|
||||
auto iter = mStreams.begin();
|
||||
while (iter != mStreams.end())
|
||||
{
|
||||
if ((*iter)->process() == false)
|
||||
|
@ -368,7 +379,7 @@ namespace MWSound
|
|||
void remove(OpenAL_SoundStream* stream)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
|
||||
auto iter = std::find(mStreams.begin(), mStreams.end(), stream);
|
||||
if (iter != mStreams.end())
|
||||
mStreams.erase(iter);
|
||||
}
|
||||
|
@ -379,9 +390,69 @@ namespace MWSound
|
|||
mStreams.clear();
|
||||
}
|
||||
|
||||
StreamThread(const StreamThread& rhs) = delete;
|
||||
StreamThread& operator=(const StreamThread& rhs) = delete;
|
||||
};
|
||||
|
||||
class OpenAL_Output::DefaultDeviceThread
|
||||
{
|
||||
public:
|
||||
std::basic_string<ALCchar> mCurrentName;
|
||||
|
||||
private:
|
||||
StreamThread(const StreamThread& rhs);
|
||||
StreamThread& operator=(const StreamThread& rhs);
|
||||
OpenAL_Output& mOutput;
|
||||
|
||||
std::atomic<bool> mQuitNow;
|
||||
std::mutex mMutex;
|
||||
std::condition_variable mCondVar;
|
||||
std::thread mThread;
|
||||
|
||||
DefaultDeviceThread(const DefaultDeviceThread&) = delete;
|
||||
DefaultDeviceThread& operator=(const DefaultDeviceThread&) = delete;
|
||||
|
||||
void run()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
while (!mQuitNow)
|
||||
{
|
||||
{
|
||||
const std::lock_guard<std::mutex> openLock(mOutput.mReopenMutex);
|
||||
auto defaultName = getDeviceName(nullptr);
|
||||
if (mCurrentName != defaultName)
|
||||
{
|
||||
Log(Debug::Info) << "Default audio device changed";
|
||||
ALCboolean reopened
|
||||
= alcReopenDeviceSOFT(mOutput.mDevice, nullptr, mOutput.mContextAttributes.data());
|
||||
if (reopened == AL_FALSE)
|
||||
{
|
||||
mCurrentName = defaultName;
|
||||
Log(Debug::Warning) << "Failed to switch to new audio device";
|
||||
}
|
||||
else
|
||||
mCurrentName = getDeviceName(mOutput.mDevice);
|
||||
}
|
||||
}
|
||||
mCondVar.wait_for(lock, std::chrono::seconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DefaultDeviceThread(OpenAL_Output& output, std::basic_string_view<ALCchar> name)
|
||||
: mCurrentName(name)
|
||||
, mOutput(output)
|
||||
, mQuitNow(false)
|
||||
, mThread([this] { run(); })
|
||||
{
|
||||
}
|
||||
|
||||
~DefaultDeviceThread()
|
||||
{
|
||||
mQuitNow = true;
|
||||
mMutex.lock();
|
||||
mMutex.unlock();
|
||||
mCondVar.notify_all();
|
||||
mThread.join();
|
||||
}
|
||||
};
|
||||
|
||||
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
|
||||
|
@ -614,7 +685,7 @@ namespace MWSound
|
|||
|
||||
void OpenAL_Output::onDisconnect()
|
||||
{
|
||||
if (!mInitialized)
|
||||
if (!mInitialized || !alcReopenDeviceSOFT)
|
||||
return;
|
||||
const std::lock_guard<std::mutex> lock(mReopenMutex);
|
||||
Log(Debug::Warning) << "Audio device disconnected, attempting to reopen...";
|
||||
|
@ -623,6 +694,12 @@ namespace MWSound
|
|||
reopened = alcReopenDeviceSOFT(mDevice, nullptr, mContextAttributes.data());
|
||||
if (reopened == AL_FALSE)
|
||||
Log(Debug::Error) << "Failed to reopen audio device";
|
||||
else
|
||||
{
|
||||
Log(Debug::Info) << "Reopened audio device";
|
||||
if (mDefaultDeviceThread)
|
||||
mDefaultDeviceThread->mCurrentName = getDeviceName(mDevice);
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenAL_Output::init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode)
|
||||
|
@ -647,11 +724,7 @@ namespace MWSound
|
|||
return false;
|
||||
}
|
||||
|
||||
const ALCchar* name = nullptr;
|
||||
if (alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
|
||||
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
|
||||
if (alcGetError(mDevice) != AL_NO_ERROR || !name)
|
||||
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
|
||||
auto name = getDeviceName(mDevice);
|
||||
Log(Debug::Info) << "Opened \"" << name << "\"";
|
||||
|
||||
ALCint major = 0, minor = 0;
|
||||
|
@ -722,9 +795,9 @@ namespace MWSound
|
|||
{
|
||||
getALFunc(alEventControlSOFT, "alEventControlSOFT");
|
||||
getALFunc(alEventCallbackSOFT, "alEventCallbackSOFT");
|
||||
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_reopen_device"))
|
||||
getALFunc(alcReopenDeviceSOFT, "alcReopenDeviceSOFT");
|
||||
}
|
||||
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_reopen_device"))
|
||||
getALFunc(alcReopenDeviceSOFT, "alcReopenDeviceSOFT");
|
||||
if (alEventControlSOFT)
|
||||
{
|
||||
static const std::array<ALenum, 1> events{ { AL_EVENT_TYPE_DISCONNECTED_SOFT } };
|
||||
|
@ -733,6 +806,14 @@ namespace MWSound
|
|||
}
|
||||
else
|
||||
Log(Debug::Warning) << "Cannot detect audio device changes";
|
||||
if (mDeviceName.empty() && !name.empty())
|
||||
{
|
||||
// If we opened the default device, switch devices if a new default is selected
|
||||
if (alcReopenDeviceSOFT)
|
||||
mDefaultDeviceThread = std::make_unique<DefaultDeviceThread>(*this, name);
|
||||
else
|
||||
Log(Debug::Warning) << "Cannot switch audio devices if the default changes";
|
||||
}
|
||||
|
||||
if (!ALC.SOFT_HRTF)
|
||||
Log(Debug::Warning) << "HRTF status unavailable";
|
||||
|
@ -892,6 +973,7 @@ namespace MWSound
|
|||
void OpenAL_Output::deinit()
|
||||
{
|
||||
mStreamThread->removeAll();
|
||||
mDefaultDeviceThread.release();
|
||||
|
||||
for (ALuint source : mFreeSources)
|
||||
alDeleteSources(1, &source);
|
||||
|
|
|
@ -58,6 +58,9 @@ namespace MWSound
|
|||
std::vector<ALCint> mContextAttributes;
|
||||
std::mutex mReopenMutex;
|
||||
|
||||
class DefaultDeviceThread;
|
||||
std::unique_ptr<DefaultDeviceThread> mDefaultDeviceThread;
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue