Merge pull request #470 from Foaly/MultiSoundInput
Added support for selecting the audio capture device (fixes #220)
This commit is contained in:
commit
db77b76d91
@ -32,6 +32,7 @@
|
||||
#include <SFML/System/Thread.hpp>
|
||||
#include <SFML/System/Time.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -59,13 +60,20 @@ public :
|
||||
/// This function uses its own thread so that it doesn't block
|
||||
/// the rest of the program while the capture runs.
|
||||
/// Please note that only one capture can happen at the same time.
|
||||
/// You can select which capture device will be used, by passing
|
||||
/// the name to the setDevice() method. If none was selected
|
||||
/// before, the default capture device will be used. You can get a
|
||||
/// list of the names of all available capture devices by calling
|
||||
/// getAvailableDevices().
|
||||
///
|
||||
/// \param sampleRate Desired capture rate, in number of samples per second
|
||||
///
|
||||
/// \see stop
|
||||
/// \return True, if start of capture was successful
|
||||
///
|
||||
/// \see stop, getAvailableDevices
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void start(unsigned int sampleRate = 44100);
|
||||
bool start(unsigned int sampleRate = 44100);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Stop the capture
|
||||
@ -87,6 +95,54 @@ public :
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int getSampleRate() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get a list of the names of all availabe audio capture devices
|
||||
///
|
||||
/// This function returns a vector of strings, containing
|
||||
/// the names of all availabe audio capture devices.
|
||||
///
|
||||
/// \return A vector of strings containing the names
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static std::vector<std::string> getAvailableDevices();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the name of the default audio capture device
|
||||
///
|
||||
/// This function returns the name of the default audio
|
||||
/// capture device. If none is available, an empty string
|
||||
/// is returned.
|
||||
///
|
||||
/// \return The name of the default audio capture device
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static std::string getDefaultDevice();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the audio capture device
|
||||
///
|
||||
/// This function sets the audio capture device to the device
|
||||
/// with the given \a name. It can be called on the fly (i.e:
|
||||
/// while recording). If you do so while recording and
|
||||
/// opening the device fails, it stops the recording.
|
||||
///
|
||||
/// \param The name of the audio capture device
|
||||
///
|
||||
/// \return True, if it was able to set the requested device
|
||||
///
|
||||
/// \see getAvailableDevices, getDefaultDevice
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool setDevice(const std::string& name);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the name of the current audio capture device
|
||||
///
|
||||
/// \return The name of the current audio capture device
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& getDevice() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if the system supports audio capture
|
||||
///
|
||||
@ -203,8 +259,9 @@ private :
|
||||
Thread m_thread; ///< Thread running the background recording task
|
||||
std::vector<Int16> m_samples; ///< Buffer to store captured samples
|
||||
unsigned int m_sampleRate; ///< Sample rate
|
||||
sf::Time m_processingInterval; ///< Time period between calls to onProcessSamples
|
||||
sf::Time m_processingInterval; ///< Time period between calls to onProcessSamples
|
||||
bool m_isCapturing; ///< Capturing state
|
||||
std::string m_deviceName; ///< Name of the audio capture device
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
@ -244,10 +301,17 @@ private :
|
||||
/// availability with the isAvailable() function. If it returns
|
||||
/// false, then any attempt to use an audio recorder will fail.
|
||||
///
|
||||
/// If you have multiple sound input devices connected to your
|
||||
/// computer (for example: microphone, external soundcard, webcam mic, ...)
|
||||
/// you can get a list of all available devices throught the
|
||||
/// getAvailableDevices() function. You can then select a device
|
||||
/// by calling setDevice() with the appropiate device. Otherwise
|
||||
/// the default capturing device will be used.
|
||||
///
|
||||
/// It is important to note that the audio capture happens in a
|
||||
/// separate thread, so that it doesn't block the rest of the
|
||||
/// program. In particular, the onProcessSamples and onStop
|
||||
/// virtual functions (but not onStart) will be called
|
||||
/// program. In particular, the onProcessSamples virtual function
|
||||
/// (but not onStart and not onStop) will be called
|
||||
/// from this separate thread. It is important to keep this in
|
||||
/// mind, because you may have to take care of synchronization
|
||||
/// issues if you share data between threads.
|
||||
@ -285,7 +349,10 @@ private :
|
||||
/// if (CustomRecorder::isAvailable())
|
||||
/// {
|
||||
/// CustomRecorder recorder;
|
||||
/// recorder.start();
|
||||
///
|
||||
/// if (!recorder.start())
|
||||
/// return -1;
|
||||
///
|
||||
/// ...
|
||||
/// recorder.stop();
|
||||
/// }
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <SFML/Audio/ALCheck.hpp>
|
||||
#include <SFML/System/Sleep.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4355) // 'this' used in base member initializer list
|
||||
@ -51,6 +52,9 @@ m_processingInterval(milliseconds(100)),
|
||||
m_isCapturing (false)
|
||||
{
|
||||
priv::ensureALInit();
|
||||
|
||||
// Set the device name to the default device
|
||||
m_deviceName = getDefaultDevice();
|
||||
}
|
||||
|
||||
|
||||
@ -62,28 +66,28 @@ SoundRecorder::~SoundRecorder()
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SoundRecorder::start(unsigned int sampleRate)
|
||||
bool SoundRecorder::start(unsigned int sampleRate)
|
||||
{
|
||||
// Check if the device can do audio capture
|
||||
if (!isAvailable())
|
||||
{
|
||||
err() << "Failed to start capture : your system cannot capture audio data (call SoundRecorder::isAvailable to check it)" << std::endl;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that another capture is not already running
|
||||
if (captureDevice)
|
||||
{
|
||||
err() << "Trying to start audio capture, but another capture is already running" << std::endl;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the capture device for capturing 16 bits mono samples
|
||||
captureDevice = alcCaptureOpenDevice(NULL, sampleRate, AL_FORMAT_MONO16, sampleRate);
|
||||
captureDevice = alcCaptureOpenDevice(m_deviceName.c_str(), sampleRate, AL_FORMAT_MONO16, sampleRate);
|
||||
if (!captureDevice)
|
||||
{
|
||||
err() << "Failed to open the audio capture device" << std::endl;
|
||||
return;
|
||||
err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear the array of samples
|
||||
@ -101,7 +105,11 @@ void SoundRecorder::start(unsigned int sampleRate)
|
||||
// Start the capture in a new thread, to avoid blocking the main thread
|
||||
m_isCapturing = true;
|
||||
m_thread.launch();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -111,6 +119,9 @@ void SoundRecorder::stop()
|
||||
// Stop the capturing thread
|
||||
m_isCapturing = false;
|
||||
m_thread.wait();
|
||||
|
||||
// Notify derived class
|
||||
onStop();
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +132,77 @@ unsigned int SoundRecorder::getSampleRate() const
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::vector<std::string> SoundRecorder::getAvailableDevices()
|
||||
{
|
||||
std::vector<std::string> deviceNameList;
|
||||
|
||||
const ALchar *deviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
if (deviceList)
|
||||
{
|
||||
while (*deviceList)
|
||||
{
|
||||
deviceNameList.push_back(deviceList);
|
||||
deviceList += std::strlen(deviceList) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return deviceNameList;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::string SoundRecorder::getDefaultDevice()
|
||||
{
|
||||
return alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundRecorder::setDevice(const std::string& name)
|
||||
{
|
||||
// Store the device name
|
||||
if (name.empty())
|
||||
m_deviceName = getDefaultDevice();
|
||||
else
|
||||
m_deviceName = name;
|
||||
|
||||
if (m_isCapturing)
|
||||
{
|
||||
// Stop the capturing thread
|
||||
m_isCapturing = false;
|
||||
m_thread.wait();
|
||||
|
||||
// Open the requested capture device for capturing 16 bits mono samples
|
||||
captureDevice = alcCaptureOpenDevice(name.c_str(), m_sampleRate, AL_FORMAT_MONO16, m_sampleRate);
|
||||
if (!captureDevice)
|
||||
{
|
||||
// Notify derived class
|
||||
onStop();
|
||||
|
||||
err() << "Failed to open the audio capture device with the name: " << m_deviceName << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start the capture
|
||||
alcCaptureStart(captureDevice);
|
||||
|
||||
// Start the capture in a new thread, to avoid blocking the main thread
|
||||
m_isCapturing = true;
|
||||
m_thread.launch();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& SoundRecorder::getDevice() const
|
||||
{
|
||||
return m_deviceName;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SoundRecorder::isAvailable()
|
||||
{
|
||||
@ -165,9 +247,6 @@ void SoundRecorder::record()
|
||||
|
||||
// Capture is finished : clean up everything
|
||||
cleanup();
|
||||
|
||||
// Notify derived class
|
||||
onStop();
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user