Make sure the recording thread in sf::SoundRecorder is stopped before sf::SoundBufferRecorder is destroyed.

Fixes a "pure virtual method called" crash.
Also updated the documentation and the VoIP example.
This commit is contained in:
Maximilian Wagenbach 2015-10-02 14:49:00 +02:00 committed by Lukas Dürrenberger
parent e00d160224
commit 1ee6d1dbc6
5 changed files with 54 additions and 10 deletions

View File

@ -32,10 +32,22 @@ public:
{ {
} }
////////////////////////////////////////////////////////////
/// Destructor
///
/// \see SoundRecorder::~SoundRecorder()
///
////////////////////////////////////////////////////////////
~NetworkRecorder()
{
// Make sure to stop the recording thread
stop();
}
private: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// /see SoundRecorder::OnStart /// \see SoundRecorder::onStart
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool onStart() virtual bool onStart()
@ -52,7 +64,7 @@ private:
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// /see SoundRecorder::ProcessSamples /// \see SoundRecorder::onProcessSamples
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual bool onProcessSamples(const sf::Int16* samples, std::size_t sampleCount) virtual bool onProcessSamples(const sf::Int16* samples, std::size_t sampleCount)
@ -67,7 +79,7 @@ private:
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// /see SoundRecorder::OnStop /// \see SoundRecorder::onStop
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual void onStop() virtual void onStop()
@ -98,7 +110,7 @@ private:
void doClient(unsigned short port) void doClient(unsigned short port)
{ {
// Check that the device can capture audio // Check that the device can capture audio
if (sf::SoundRecorder::isAvailable() == false) if (!sf::SoundRecorder::isAvailable())
{ {
std::cout << "Sorry, audio capture is not supported by your system" << std::endl; std::cout << "Sorry, audio capture is not supported by your system" << std::endl;
return; return;

View File

@ -45,6 +45,12 @@ class SFML_AUDIO_API SoundBufferRecorder : public SoundRecorder
{ {
public: public:
////////////////////////////////////////////////////////////
/// \brief destructor
///
////////////////////////////////////////////////////////////
~SoundBufferRecorder();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the sound buffer containing the captured audio data /// \brief Get the sound buffer containing the captured audio data
/// ///

View File

@ -316,11 +316,20 @@ private:
/// from this separate thread. It is important to keep this in /// from this separate thread. It is important to keep this in
/// mind, because you may have to take care of synchronization /// mind, because you may have to take care of synchronization
/// issues if you share data between threads. /// issues if you share data between threads.
/// Another thing to bear in mind is that you must call stop()
/// in the destructor of your derived class, so that the recording
/// thread finishes before your object is destroyed.
/// ///
/// Usage example: /// Usage example:
/// \code /// \code
/// class CustomRecorder : public sf::SoundRecorder /// class CustomRecorder : public sf::SoundRecorder
/// { /// {
/// ~CustomRecorder()
/// {
/// // Make sure to stop the recording thread
/// stop();
/// }
///
/// virtual bool onStart() // optional /// virtual bool onStart() // optional
/// { /// {
/// // Initialize whatever has to be done before the capture starts /// // Initialize whatever has to be done before the capture starts

View File

@ -32,6 +32,14 @@
namespace sf namespace sf
{ {
////////////////////////////////////////////////////////////
SoundBufferRecorder::~SoundBufferRecorder()
{
// Make sure to stop the recording thread
stop();
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool SoundBufferRecorder::onStart() bool SoundBufferRecorder::onStart()
{ {

View File

@ -31,6 +31,7 @@
#include <SFML/System/Sleep.hpp> #include <SFML/System/Sleep.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <cstring> #include <cstring>
#include <cassert>
#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
@ -59,7 +60,12 @@ m_deviceName (getDefaultDevice())
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SoundRecorder::~SoundRecorder() SoundRecorder::~SoundRecorder()
{ {
// Nothing to do // This assertion is triggered if the recording is still running while
// the object is destroyed. It ensures that stop() is called in the
// destructor of the derived class, which makes sure that the recording
// thread finishes before the derived object is destroyed. Otherwise a
// "pure virtual method called" exception is triggered.
assert(!m_isCapturing && "You must call stop() in the destructor of your derived class, so that the recording thread finishes before your object is destroyed.");
} }
@ -114,12 +120,15 @@ bool SoundRecorder::start(unsigned int sampleRate)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SoundRecorder::stop() void SoundRecorder::stop()
{ {
// Stop the capturing thread // Stop the capturing thread if there is one
m_isCapturing = false; if (m_isCapturing)
m_thread.wait(); {
m_isCapturing = false;
m_thread.wait();
// Notify derived class // Notify derived class
onStop(); onStop();
}
} }