Abort looping in SoundStream::streamData if an OpenAL error occurs that would have caused it to never terminate.

Backports #2026 and fixes #1831 for SFML 2
This commit is contained in:
Lukas Dürrenberger 2023-11-14 22:42:06 +01:00 committed by Chris Thrasher
parent 1f345d7d25
commit c7d1112234
3 changed files with 41 additions and 0 deletions

View File

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Audio/ALCheck.hpp> #include <SFML/Audio/ALCheck.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/ThreadLocalPtr.hpp>
#include <string> #include <string>
#if defined(__APPLE__) #if defined(__APPLE__)
@ -37,6 +38,15 @@
#endif #endif
#endif #endif
namespace
{
// A nested named namespace is used here to allow unity builds of SFML.
namespace AlCheckImpl
{
sf::ThreadLocalPtr<ALenum> lastError(AL_NO_ERROR);
}
}
namespace sf namespace sf
{ {
namespace priv namespace priv
@ -49,6 +59,8 @@ void alCheckError(const char* file, unsigned int line, const char* expression)
if (errorCode != AL_NO_ERROR) if (errorCode != AL_NO_ERROR)
{ {
AlCheckImpl::lastError = &errorCode;
std::string fileString = file; std::string fileString = file;
std::string error = "Unknown error"; std::string error = "Unknown error";
std::string description = "No description"; std::string description = "No description";
@ -101,6 +113,15 @@ void alCheckError(const char* file, unsigned int line, const char* expression)
} }
} }
////////////////////////////////////////////////////////////
ALenum alGetLastErrorImpl()
{
ALenum lastError = AlCheckImpl::lastError ? *AlCheckImpl::lastError : AL_NO_ERROR;
AlCheckImpl::lastError = AL_NO_ERROR;
return lastError;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -55,11 +55,13 @@ namespace priv
// If in debug mode, perform a test on every call // If in debug mode, perform a test on every call
// The do-while loop is needed so that alCheck can be used as a single statement in if/else branches // The do-while loop is needed so that alCheck can be used as a single statement in if/else branches
#define alCheck(expr) do { expr; sf::priv::alCheckError(__FILE__, __LINE__, #expr); } while (false) #define alCheck(expr) do { expr; sf::priv::alCheckError(__FILE__, __LINE__, #expr); } while (false)
#define alGetLastError sf::priv::alGetLastErrorImpl
#else #else
// Else, we don't add any overhead // Else, we don't add any overhead
#define alCheck(expr) (expr) #define alCheck(expr) (expr)
#define alGetLastError alGetError
#endif #endif
@ -74,6 +76,15 @@ namespace priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void alCheckError(const char* file, unsigned int line, const char* expression); void alCheckError(const char* file, unsigned int line, const char* expression);
////////////////////////////////////////////////////////////
/// Get the last OpenAL error on this thread
///
/// \return The last OpenAL error on this thread
///
////////////////////////////////////////////////////////////
ALenum alGetLastErrorImpl();
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -404,6 +404,15 @@ void SoundStream::streamData()
} }
} }
// Check if any error has occurred
if (alGetLastError() != AL_NO_ERROR)
{
// Abort streaming (exit main loop)
Lock lock(m_threadMutex);
m_isStreaming = false;
break;
}
// Leave some time for the other threads if the stream is still playing // Leave some time for the other threads if the stream is still playing
if (SoundSource::getStatus() != Stopped) if (SoundSource::getStatus() != Stopped)
sleep(m_processingInterval); sleep(m_processingInterval);