diff --git a/include/SFML/Audio/SoundRecorder.hpp b/include/SFML/Audio/SoundRecorder.hpp index 0344e096..5b492a44 100644 --- a/include/SFML/Audio/SoundRecorder.hpp +++ b/include/SFML/Audio/SoundRecorder.hpp @@ -32,6 +32,7 @@ #include #include #include +#include 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 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 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(); /// } diff --git a/src/SFML/Audio/SoundRecorder.cpp b/src/SFML/Audio/SoundRecorder.cpp index a17c006a..bb7a0508 100644 --- a/src/SFML/Audio/SoundRecorder.cpp +++ b/src/SFML/Audio/SoundRecorder.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #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 SoundRecorder::getAvailableDevices() +{ + std::vector 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(); }