23 #include <portaudio.h>
35 #define SLEEP_TIME 0.005f
38 #define PA_SAMPLE_TYPE paFloat32
40 #define SAMPLE_SILENCE (0.0f)
42 #define PA_SAMPLE_TYPE paInt16
44 #define SAMPLE_SILENCE (0)
46 #define PA_SAMPLE_TYPE paInt8
48 #define SAMPLE_SILENCE (0)
50 #define PA_SAMPLE_TYPE paUInt8
51 typedef unsigned char SAMPLE;
52 #define SAMPLE_SILENCE (128)
53 #define SAMPLE_UNSIGNED
67 unsigned long framesPerBuffer,
68 const PaStreamCallbackTimeInfo* timeInfo,
69 PaStreamCallbackFlags statusFlags,
74 int finished = paComplete;
78 auto* wptr = (
SAMPLE*)outputBuffer;
88 if( framesLeft/ num_play_channels < framesPerBuffer )
91 for( i=0; i<framesLeft/ num_play_channels; i++ )
93 *wptr++ = playdata->
read();
94 if( num_play_channels == 2 ) *wptr++ = playdata->
read();
95 for (
size_t chs=2; chs<num_play_channels; chs++) playdata->
read();
97 for( ; i<framesPerBuffer; i++ )
100 if(num_play_channels == 2 ) *wptr++ = 0;
102 #ifdef STOP_PLAY_ON_EMPTY_BUFFER
106 finished = paComplete;
108 finished = paContinue;
114 yCDebug(PORTAUDIOPLAYER) <<
"Reading" << framesPerBuffer*2 <<
"bytes from the circular buffer";
116 for( i=0; i<framesPerBuffer; i++ )
118 *wptr++ = playdata->
read();
119 if( num_play_channels == 2 ) *wptr++ = playdata->
read();
120 for (
size_t chs=2; chs<num_play_channels; chs++) playdata->
read();
124 finished = paContinue;
129 yCError(PORTAUDIOPLAYER,
"No read operations requested, aborting");
134 something_to_play(false),
157 err = Pa_StartStream(
stream );
158 if( err != paNoError ) {handleError();
return;}
160 while( ( err = Pa_IsStreamActive(
stream ) ) == 1 )
166 yCDebug(PORTAUDIOPLAYER) <<
"The playback stream has been stopped";
174 err = Pa_StopStream(
stream );
189 void PlayStreamThread::handleError()
192 if( err != paNoError )
194 yCError(PORTAUDIOPLAYER,
"An error occurred while using the portaudio stream" );
195 yCError(PORTAUDIOPLAYER,
"Error number: %d", err );
196 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText( err ) );
203 m_playDataBuffer(nullptr),
204 m_system_resource(nullptr),
205 renderMode(RENDER_APPEND)
207 memset(&m_outputParameters, 0,
sizeof(PaStreamParameters));
219 m_driverConfig.
cfg_samples = config.
check(
"samples",
Value(0),
"number of samples per network packet (0=automatic). For chunks of 1 second of recording set samples=rate. Channels number is handled internally.").asInt32();
223 if (config.
check(
"render_mode_append"))
227 if (config.
check(
"render_mode_immediate"))
247 if (m_playDataBuffer ==
nullptr)
250 m_err = Pa_Initialize();
251 if(m_err != paNoError )
253 yCError(PORTAUDIOPLAYER,
"portaudio system failed to initialize");
260 m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_outputParameters.device )->defaultLowOutputLatency;
261 m_outputParameters.hostApiSpecificStreamInfo =
nullptr;
263 m_err = Pa_OpenStream(
273 if(m_err != paNoError )
275 yCError(PORTAUDIOPLAYER,
"An error occurred while using the portaudio stream" );
276 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
277 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
281 m_pThread.
stream = m_stream;
284 return (m_err==paNoError);
290 m_playDataBuffer->
clear();
292 if(m_err != paNoError )
294 yCError(PORTAUDIOPLAYER,
"An error occurred while using the portaudio stream" );
295 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
296 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
303 if (m_stream !=
nullptr)
305 m_err = Pa_CloseStream(m_stream );
306 if(m_err != paNoError )
308 yCError(PORTAUDIOPLAYER,
"An error occurred while closing the portaudio stream" );
309 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
310 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
314 if (this->m_playDataBuffer !=
nullptr)
316 delete this->m_playDataBuffer;
317 this->m_playDataBuffer =
nullptr;
320 return (m_err==paNoError);
325 yCInfo(PORTAUDIOPLAYER,
"=== Stopping and clearing stream.==="); fflush(stdout);
326 m_err = Pa_StopStream(m_stream );
327 if(m_err != paNoError )
329 yCError(PORTAUDIOPLAYER,
"abortSound: error occurred while stopping the portaudio stream" );
330 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
331 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
334 m_playDataBuffer->
clear();
336 return (m_err==paNoError);
341 m_playDataBuffer->
clear();
347 for (
size_t i=0; i<num_samples; i++)
348 for (
size_t j=0; j<num_channels; j++)
349 m_playDataBuffer->
write (sound.
get(i,j));
358 std::lock_guard<std::mutex> lock(m_mutex);
364 yCError(PORTAUDIOPLAYER) <<
"received a bad audio sample of frequency 0";
369 yCError(PORTAUDIOPLAYER) <<
"received a bad audio sample with 0 channels";
373 if (freq != this->m_config.
cfg_rate ||
374 chans != this->m_config.cfg_playChannels)
377 while (Pa_IsStreamStopped(m_stream )==0)
383 yCInfo(PORTAUDIOPLAYER,
"***** audio driver configuration changed, resetting");
385 chans <<
"channels, " << freq <<
" Hz";
392 yCError(PORTAUDIOPLAYER,
"error occurred during audio driver reconfiguration, aborting");
411 for (
size_t i=0; i<num_samples; i++)
412 for (
size_t j=0; j<num_channels; j++)
413 m_playDataBuffer->
write (sound.
get(i,j));
422 size = this->m_playDataBuffer->
size();
435 std::lock_guard<std::mutex> lock(m_mutex);
436 this->m_playDataBuffer->
clear();
442 std::lock_guard<std::mutex> lock(m_mutex);
449 std::lock_guard<std::mutex> lock(m_mutex);
#define DEFAULT_FRAMES_PER_BUFFER
#define DEFAULT_NUM_CHANNELS
#define DEFAULT_SAMPLE_RATE
static int bufferIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
void run() override
Main body of the new thread.
bool threadInit() override
Initialization method.
void threadRelease() override
Release method.
bool resetPlaybackAudioBuffer() override
bool getPlaybackAudioBufferCurrentSize(yarp::dev::AudioBufferSize &size) override
bool appendSound(const yarp::sig::Sound &sound)
bool stopPlayback() override
Stop the playback.
enum PortAudioPlayerDeviceDriver::@91 renderMode
bool getPlaybackAudioBufferMaxSize(yarp::dev::AudioBufferSize &size) override
bool renderSound(const yarp::sig::Sound &sound) override
Render a sound using a device (i.e.
~PortAudioPlayerDeviceDriver() override
PortAudioPlayerDeviceDriver()
bool close() override
Close the DeviceDriver.
bool startPlayback() override
Start the playback.
PortAudioPlayerDeviceDriverSettings m_driverConfig
bool immediateSound(const yarp::sig::Sound &sound)
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
yarp::dev::AudioBufferSize getMaxSize()
A base class for nested structures that can be searched.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
static void delaySystem(double seconds)
bool stop()
Stop the thread.
bool isStopping()
Returns true if the thread is stopping (Thread::stop has been called).
bool start()
Start the new thread running.
A single value (typically within a Bottle).
Class for storing sounds.
size_t getChannels() const
Get the number of channels of the sound.
int getFrequency() const
Get the frequency of the sound (i.e.
audio_sample get(size_t sample, size_t channel=0) const
size_t getSamples() const
Get the number of samples contained in the sound.
#define yCInfo(component,...)
#define yCError(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
An interface for the device drivers.
yarp::dev::CircularAudioBuffer< unsigned short int > CircularAudioBuffer_16t
void delay(double seconds)
Wait for a certain number of seconds.
An interface to the operating system, including Port based communication.