mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 17:59:56 +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 #3842: Body part skeletons override the main skeleton
|
||||||
Bug #4127: Weapon animation looks choppy
|
Bug #4127: Weapon animation looks choppy
|
||||||
Bug #4204: Dead slaughterfish doesn't float to water surface after loading saved game
|
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 #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 #4816: GetWeaponDrawn returns 1 before weapon is attached
|
||||||
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -165,6 +166,17 @@ namespace
|
||||||
getALError();
|
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
|
namespace MWSound
|
||||||
|
@ -314,8 +326,7 @@ namespace MWSound
|
||||||
//
|
//
|
||||||
struct OpenAL_Output::StreamThread
|
struct OpenAL_Output::StreamThread
|
||||||
{
|
{
|
||||||
typedef std::vector<OpenAL_SoundStream*> StreamVec;
|
std::vector<OpenAL_SoundStream*> mStreams;
|
||||||
StreamVec mStreams;
|
|
||||||
|
|
||||||
std::atomic<bool> mQuitNow;
|
std::atomic<bool> mQuitNow;
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
|
@ -342,7 +353,7 @@ namespace MWSound
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
while (!mQuitNow)
|
while (!mQuitNow)
|
||||||
{
|
{
|
||||||
StreamVec::iterator iter = mStreams.begin();
|
auto iter = mStreams.begin();
|
||||||
while (iter != mStreams.end())
|
while (iter != mStreams.end())
|
||||||
{
|
{
|
||||||
if ((*iter)->process() == false)
|
if ((*iter)->process() == false)
|
||||||
|
@ -368,7 +379,7 @@ namespace MWSound
|
||||||
void remove(OpenAL_SoundStream* stream)
|
void remove(OpenAL_SoundStream* stream)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
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())
|
if (iter != mStreams.end())
|
||||||
mStreams.erase(iter);
|
mStreams.erase(iter);
|
||||||
}
|
}
|
||||||
|
@ -379,9 +390,69 @@ namespace MWSound
|
||||||
mStreams.clear();
|
mStreams.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StreamThread(const StreamThread& rhs) = delete;
|
||||||
|
StreamThread& operator=(const StreamThread& rhs) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenAL_Output::DefaultDeviceThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::basic_string<ALCchar> mCurrentName;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StreamThread(const StreamThread& rhs);
|
OpenAL_Output& mOutput;
|
||||||
StreamThread& operator=(const StreamThread& rhs);
|
|
||||||
|
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)
|
OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
|
||||||
|
@ -614,7 +685,7 @@ namespace MWSound
|
||||||
|
|
||||||
void OpenAL_Output::onDisconnect()
|
void OpenAL_Output::onDisconnect()
|
||||||
{
|
{
|
||||||
if (!mInitialized)
|
if (!mInitialized || !alcReopenDeviceSOFT)
|
||||||
return;
|
return;
|
||||||
const std::lock_guard<std::mutex> lock(mReopenMutex);
|
const std::lock_guard<std::mutex> lock(mReopenMutex);
|
||||||
Log(Debug::Warning) << "Audio device disconnected, attempting to reopen...";
|
Log(Debug::Warning) << "Audio device disconnected, attempting to reopen...";
|
||||||
|
@ -623,6 +694,12 @@ namespace MWSound
|
||||||
reopened = alcReopenDeviceSOFT(mDevice, nullptr, mContextAttributes.data());
|
reopened = alcReopenDeviceSOFT(mDevice, nullptr, mContextAttributes.data());
|
||||||
if (reopened == AL_FALSE)
|
if (reopened == AL_FALSE)
|
||||||
Log(Debug::Error) << "Failed to reopen audio device";
|
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)
|
bool OpenAL_Output::init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode)
|
||||||
|
@ -647,11 +724,7 @@ namespace MWSound
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ALCchar* name = nullptr;
|
auto name = getDeviceName(mDevice);
|
||||||
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);
|
|
||||||
Log(Debug::Info) << "Opened \"" << name << "\"";
|
Log(Debug::Info) << "Opened \"" << name << "\"";
|
||||||
|
|
||||||
ALCint major = 0, minor = 0;
|
ALCint major = 0, minor = 0;
|
||||||
|
@ -722,9 +795,9 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
getALFunc(alEventControlSOFT, "alEventControlSOFT");
|
getALFunc(alEventControlSOFT, "alEventControlSOFT");
|
||||||
getALFunc(alEventCallbackSOFT, "alEventCallbackSOFT");
|
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)
|
if (alEventControlSOFT)
|
||||||
{
|
{
|
||||||
static const std::array<ALenum, 1> events{ { AL_EVENT_TYPE_DISCONNECTED_SOFT } };
|
static const std::array<ALenum, 1> events{ { AL_EVENT_TYPE_DISCONNECTED_SOFT } };
|
||||||
|
@ -733,6 +806,14 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Log(Debug::Warning) << "Cannot detect audio device changes";
|
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)
|
if (!ALC.SOFT_HRTF)
|
||||||
Log(Debug::Warning) << "HRTF status unavailable";
|
Log(Debug::Warning) << "HRTF status unavailable";
|
||||||
|
@ -892,6 +973,7 @@ namespace MWSound
|
||||||
void OpenAL_Output::deinit()
|
void OpenAL_Output::deinit()
|
||||||
{
|
{
|
||||||
mStreamThread->removeAll();
|
mStreamThread->removeAll();
|
||||||
|
mDefaultDeviceThread.release();
|
||||||
|
|
||||||
for (ALuint source : mFreeSources)
|
for (ALuint source : mFreeSources)
|
||||||
alDeleteSources(1, &source);
|
alDeleteSources(1, &source);
|
||||||
|
|
|
@ -58,6 +58,9 @@ namespace MWSound
|
||||||
std::vector<ALCint> mContextAttributes;
|
std::vector<ALCint> mContextAttributes;
|
||||||
std::mutex mReopenMutex;
|
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 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,
|
void initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, ALfloat gain,
|
||||||
ALfloat pitch, bool loop, bool useenv);
|
ALfloat pitch, bool loop, bool useenv);
|
||||||
|
|
Loading…
Reference in a new issue