mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-03-23 03:01:08 +00:00
OpenAL: Try to reset disconnected devices, fixes #209
OpenAL devices can disconnect, and with some luck they're back after a few seconds. This especially seems to happen with Intels Windows GPU driver and display-audio when switching the resolution or enabling fullscreen, see #209 Now a disconnect is detected and we try to reset the device for 20 seconds, hoping it comes back. This needs at least openal-soft 1.17.0 to build and 1.20.0 or newer to actually work. Also added missing stub functions in openal_stub.cpp (used by dedicated server so it doesn't have to link libopenal)
This commit is contained in:
parent
964efa191d
commit
e6f3713169
4 changed files with 108 additions and 0 deletions
|
@ -2520,12 +2520,18 @@ void idSessionLocal::UpdateScreen( bool outOfSequence ) {
|
|||
idSessionLocal::Frame
|
||||
===============
|
||||
*/
|
||||
extern bool CheckOpenALDeviceAndRecoverIfNeeded();
|
||||
void idSessionLocal::Frame() {
|
||||
|
||||
if ( com_asyncSound.GetInteger() == 0 ) {
|
||||
soundSystem->AsyncUpdate( Sys_Milliseconds() );
|
||||
}
|
||||
|
||||
// DG: periodically check if sound device is still there and try to reset it if not
|
||||
// (calling this from idSoundSystem::AsyncUpdate(), which runs in a separate thread
|
||||
// by default, causes a deadlock when calling idCommon->Warning())
|
||||
CheckOpenALDeviceAndRecoverIfNeeded();
|
||||
|
||||
// Editors that completely take over the game
|
||||
if ( com_editorActive && ( com_editors & ( EDITOR_RADIANT | EDITOR_GUI ) ) ) {
|
||||
return;
|
||||
|
|
|
@ -691,6 +691,11 @@ public:
|
|||
ALuint AllocOpenALSource( idSoundChannel *chan, bool looping, bool stereo );
|
||||
void FreeOpenALSource( ALuint handle );
|
||||
|
||||
// returns true if openalDevice is still available,
|
||||
// otherwise it will try to recover the device and return false while it's gone
|
||||
// (display audio sound devices sometimes disappear for a few seconds when switching resolution)
|
||||
bool CheckDeviceAndRecoverIfNeeded();
|
||||
|
||||
idSoundCache * soundCache;
|
||||
|
||||
idSoundWorldLocal * currentSoundWorld; // the one to mix each async tic
|
||||
|
@ -747,6 +752,11 @@ public:
|
|||
// mark available during initialization, or through an explicit test
|
||||
static int EFXAvailable;
|
||||
|
||||
// DG: for CheckDeviceAndRecoverIfNeeded()
|
||||
LPALCRESETDEVICESOFT alcResetDeviceSOFT; // needs ALC_SOFT_HRTF extension
|
||||
int resetRetryCount;
|
||||
unsigned int lastCheckTime;
|
||||
|
||||
static idCVar s_noSound;
|
||||
static idCVar s_device;
|
||||
static idCVar s_quadraticFalloff;
|
||||
|
|
|
@ -277,6 +277,17 @@ void SoundSystemRestart_f( const idCmdArgs &args ) {
|
|||
soundSystem->SetMute( false );
|
||||
}
|
||||
|
||||
// DG: make this function callable from idSessionLocal::Frame() without having to
|
||||
// change the public idSoundSystem interface - that would break mod DLL compat,
|
||||
// and this is not relevant for gamecode.
|
||||
bool CheckOpenALDeviceAndRecoverIfNeeded()
|
||||
{
|
||||
if(soundSystemLocal.isInitialized)
|
||||
return soundSystemLocal.CheckDeviceAndRecoverIfNeeded();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idSoundSystemLocal::Init
|
||||
|
@ -313,6 +324,11 @@ void idSoundSystemLocal::Init() {
|
|||
|
||||
graph = NULL;
|
||||
|
||||
// DG: added these for CheckDeviceAndRecoverIfNeeded()
|
||||
alcResetDeviceSOFT = NULL;
|
||||
resetRetryCount = 0;
|
||||
lastCheckTime = 0;
|
||||
|
||||
// DG: no point in initializing OpenAL if sound is disabled with s_noSound
|
||||
if ( s_noSound.GetBool() ) {
|
||||
common->Printf( "Sound disabled with s_noSound 1 !\n" );
|
||||
|
@ -385,6 +401,14 @@ void idSoundSystemLocal::Init() {
|
|||
common->Printf( "OpenAL renderer: %s\n", alGetString(AL_RENDERER) );
|
||||
common->Printf( "OpenAL version: %s\n", alGetString(AL_VERSION) );
|
||||
|
||||
// DG: extensions needed for CheckDeviceAndRecoverIfNeeded()
|
||||
bool hasAlcExtDisconnect = alcIsExtensionPresent( openalDevice, "ALC_EXT_disconnect" ) != AL_FALSE;
|
||||
bool hasAlcSoftHrtf = alcIsExtensionPresent( openalDevice, "ALC_SOFT_HRTF" ) != AL_FALSE;
|
||||
if ( hasAlcExtDisconnect && hasAlcSoftHrtf ) {
|
||||
common->Printf( "OpenAL: found extensions for resetting disconnected devices\n" );
|
||||
alcResetDeviceSOFT = (LPALCRESETDEVICESOFT)alcGetProcAddress( openalDevice, "alcResetDeviceSOFT" );
|
||||
}
|
||||
|
||||
// try to obtain EFX extensions
|
||||
if (alcIsExtensionPresent(openalDevice, "ALC_EXT_EFX")) {
|
||||
common->Printf( "OpenAL: found EFX extension\n" );
|
||||
|
@ -570,6 +594,63 @@ bool idSoundSystemLocal::ShutdownHW() {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded
|
||||
|
||||
DG: returns true if openalDevice is still available,
|
||||
otherwise it will try to recover the device and return false while it's gone
|
||||
(display audio sound devices sometimes disappear for a few seconds when switching resolution)
|
||||
===============
|
||||
*/
|
||||
bool idSoundSystemLocal::CheckDeviceAndRecoverIfNeeded()
|
||||
{
|
||||
static const int maxRetries = 20;
|
||||
|
||||
if ( alcResetDeviceSOFT == NULL ) {
|
||||
return true; // we can't check or reset, just pretend everything is fine..
|
||||
}
|
||||
|
||||
unsigned int curTime = Sys_Milliseconds();
|
||||
if ( curTime - lastCheckTime >= 1000 ) // check once per second
|
||||
{
|
||||
lastCheckTime = curTime;
|
||||
|
||||
ALCint connected; // ALC_CONNECTED needs ALC_EXT_disconnect (we check for that in Init())
|
||||
alcGetIntegerv( openalDevice, ALC_CONNECTED, 1, &connected );
|
||||
if ( connected ) {
|
||||
resetRetryCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( resetRetryCount == 0 ) {
|
||||
common->Warning( "OpenAL device disconnected! Will try to reconnect.." );
|
||||
resetRetryCount = 1;
|
||||
} else if ( resetRetryCount > maxRetries ) { // give up after 20 seconds
|
||||
if ( resetRetryCount == maxRetries+1 ) {
|
||||
common->Warning( "OpenAL device still disconnected! Giving up!" );
|
||||
++resetRetryCount; // this makes sure the warning is only shown once
|
||||
|
||||
// TODO: can we shut down sound without things blowing up?
|
||||
// if we can, we could do that if we don't have alcResetDeviceSOFT but ALC_EXT_disconnect
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( alcResetDeviceSOFT( openalDevice, NULL ) ) {
|
||||
common->Printf( "OpenAL: resetting device succeeded!\n" );
|
||||
resetRetryCount = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
++resetRetryCount;
|
||||
return false;
|
||||
}
|
||||
|
||||
return resetRetryCount == 0; // if it's 0, state on last check was ok
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idSoundSystemLocal::GetCurrent44kHzTime
|
||||
|
|
|
@ -65,6 +65,17 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const
|
|||
return AL_FALSE;
|
||||
}
|
||||
|
||||
ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) {}
|
||||
|
||||
ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) {
|
||||
return ALC_NO_ERROR;
|
||||
}
|
||||
|
||||
ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ) { }
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* fname ) {
|
||||
|
|
Loading…
Reference in a new issue