Fixed calling SoundStream::setPlayingOffset() unpausing a paused SoundStream (#203), guard m_isStreaming by a mutex, fixed calling SoundStream::pause() before the stream thread starts not properly pausing the stream (http://en.sfml-dev.org/forums/index.php?topic=15197.0), minor documentation fix in SoundStream. Signed-off-by: binary1248 <binary1248@hotmail.com>

This commit is contained in:
Foaly 2014-05-01 04:22:53 +02:00 committed by binary1248
parent 1851dcb109
commit 09aae0240d
2 changed files with 82 additions and 21 deletions

View File

@ -32,6 +32,7 @@
#include <SFML/Audio/SoundSource.hpp> #include <SFML/Audio/SoundSource.hpp>
#include <SFML/System/Thread.hpp> #include <SFML/System/Thread.hpp>
#include <SFML/System/Time.hpp> #include <SFML/System/Time.hpp>
#include <SFML/System/Mutex.hpp>
#include <cstdlib> #include <cstdlib>
@ -65,8 +66,8 @@ public :
/// \brief Start or resume playing the audio stream /// \brief Start or resume playing the audio stream
/// ///
/// This function starts the stream if it was stopped, resumes /// This function starts the stream if it was stopped, resumes
/// it if it was paused, and restarts it from beginning if it /// it if it was paused, and restarts it from the beginning if
/// was it already playing. /// it was already playing.
/// This function uses its own thread so that it doesn't block /// This function uses its own thread so that it doesn't block
/// the rest of the program while the stream is played. /// the rest of the program while the stream is played.
/// ///
@ -282,6 +283,8 @@ private :
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Thread m_thread; ///< Thread running the background tasks Thread m_thread; ///< Thread running the background tasks
mutable Mutex m_threadMutex; ///< Thread mutex
Status m_threadStartState; ///< State the thread starts in (Playing, Paused, Stopped)
bool m_isStreaming; ///< Streaming state (true = playing, false = stopped) bool m_isStreaming; ///< Streaming state (true = playing, false = stopped)
unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data unsigned int m_buffers[BufferCount]; ///< Sound buffers used to store temporary audio data
unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...) unsigned int m_channelCount; ///< Number of channels (1 = mono, 2 = stereo, ...)

View File

@ -30,6 +30,7 @@
#include <SFML/Audio/ALCheck.hpp> #include <SFML/Audio/ALCheck.hpp>
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <SFML/System/Lock.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable : 4355) // 'this' used in base member initializer list #pragma warning(disable : 4355) // 'this' used in base member initializer list
@ -41,6 +42,8 @@ namespace sf
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundStream::SoundStream() : SoundStream::SoundStream() :
m_thread (&SoundStream::streamData, this), m_thread (&SoundStream::streamData, this),
m_threadMutex (),
m_threadStartState(Stopped),
m_isStreaming (false), m_isStreaming (false),
m_channelCount (0), m_channelCount (0),
m_sampleRate (0), m_sampleRate (0),
@ -89,6 +92,9 @@ void SoundStream::play()
return; return;
} }
{
Lock lock(m_threadMutex);
// If the sound is already playing (probably paused), just resume it // If the sound is already playing (probably paused), just resume it
if (m_isStreaming) if (m_isStreaming)
{ {
@ -96,12 +102,15 @@ void SoundStream::play()
return; return;
} }
m_isStreaming = true;
}
// Move to the beginning // Move to the beginning
onSeek(Time::Zero); onSeek(Time::Zero);
// Start updating the stream in a separate thread to avoid blocking the application // Start updating the stream in a separate thread to avoid blocking the application
m_samplesProcessed = 0; m_samplesProcessed = 0;
m_isStreaming = true; m_threadStartState = Playing;
m_thread.launch(); m_thread.launch();
} }
@ -109,6 +118,12 @@ void SoundStream::play()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::pause() void SoundStream::pause()
{ {
// Handle pause() being called before the thread has started
{
Lock lock(m_threadMutex);
m_threadStartState = Paused;
}
alCheck(alSourcePause(m_source)); alCheck(alSourcePause(m_source));
} }
@ -116,8 +131,13 @@ void SoundStream::pause()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::stop() void SoundStream::stop()
{ {
// Wait for the thread to terminate // Request the thread to terminate
{
Lock lock(m_threadMutex);
m_isStreaming = false; m_isStreaming = false;
}
// Wait for the thread to terminate
m_thread.wait(); m_thread.wait();
} }
@ -142,8 +162,13 @@ SoundStream::Status SoundStream::getStatus() const
Status status = SoundSource::getStatus(); Status status = SoundSource::getStatus();
// To compensate for the lag between play() and alSourceplay() // To compensate for the lag between play() and alSourceplay()
if ((status == Stopped) && m_isStreaming) if (status == Stopped)
status = Playing; {
Lock lock(m_threadMutex);
if (m_isStreaming)
status = m_threadStartState;
}
return status; return status;
} }
@ -152,6 +177,9 @@ SoundStream::Status SoundStream::getStatus() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::setPlayingOffset(Time timeOffset) void SoundStream::setPlayingOffset(Time timeOffset)
{ {
// Get old playing status
Status oldStatus = getStatus();
// Stop the stream // Stop the stream
stop(); stop();
@ -160,7 +188,12 @@ void SoundStream::setPlayingOffset(Time timeOffset)
// Restart streaming // Restart streaming
m_samplesProcessed = static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount); m_samplesProcessed = static_cast<Uint64>(timeOffset.asSeconds() * m_sampleRate * m_channelCount);
if (oldStatus == Stopped)
return;
m_isStreaming = true; m_isStreaming = true;
m_threadStartState = oldStatus;
m_thread.launch(); m_thread.launch();
} }
@ -199,19 +232,42 @@ bool SoundStream::getLoop() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundStream::streamData() void SoundStream::streamData()
{ {
bool requestStop = false;
{
Lock lock(m_threadMutex);
// Check if the thread was launched Stopped
if (m_threadStartState == Stopped)
{
m_isStreaming = false;
return;
}
// Create the buffers // Create the buffers
alCheck(alGenBuffers(BufferCount, m_buffers)); alCheck(alGenBuffers(BufferCount, m_buffers));
for (int i = 0; i < BufferCount; ++i) for (int i = 0; i < BufferCount; ++i)
m_endBuffers[i] = false; m_endBuffers[i] = false;
// Fill the queue // Fill the queue
bool requestStop = fillQueue(); requestStop = fillQueue();
// Play the sound // Play the sound
alCheck(alSourcePlay(m_source)); alCheck(alSourcePlay(m_source));
while (m_isStreaming) // Check if the thread was launched Paused
if (m_threadStartState == Paused)
alCheck(alSourcePause(m_source));
}
for (;;)
{ {
{
Lock lock(m_threadMutex);
if (!m_isStreaming)
break;
}
// The stream has been interrupted! // The stream has been interrupted!
if (SoundSource::getStatus() == Stopped) if (SoundSource::getStatus() == Stopped)
{ {
@ -223,6 +279,7 @@ void SoundStream::streamData()
else else
{ {
// End streaming // End streaming
Lock lock(m_threadMutex);
m_isStreaming = false; m_isStreaming = false;
} }
} }
@ -266,6 +323,7 @@ void SoundStream::streamData()
<< "and initialize() has been called correctly" << std::endl; << "and initialize() has been called correctly" << std::endl;
// Abort streaming (exit main loop) // Abort streaming (exit main loop)
Lock lock(m_threadMutex);
m_isStreaming = false; m_isStreaming = false;
requestStop = true; requestStop = true;
break; break;