10 #include <portaudio.h>
22 #define SLEEP_TIME 0.010f
25 #define PA_SAMPLE_TYPE paFloat32
27 #define SAMPLE_SILENCE (0.0f)
29 #define PA_SAMPLE_TYPE paInt16
31 #define SAMPLE_SILENCE (0)
33 #define PA_SAMPLE_TYPE paInt8
35 #define SAMPLE_SILENCE (0)
37 #define PA_SAMPLE_TYPE paUInt8
38 typedef unsigned char SAMPLE;
39 #define SAMPLE_SILENCE (128)
40 #define SAMPLE_UNSIGNED
43 #define DEFAULT_FRAMES_PER_BUFFER (512)
55 unsigned long framesPerBuffer,
56 const PaStreamCallbackTimeInfo* timeInfo,
57 PaStreamCallbackFlags statusFlags,
62 int finished = paComplete;
66 auto* wptr = (
SAMPLE*)outputBuffer;
76 if( framesLeft/ num_play_channels < framesPerBuffer )
79 for( i=0; i<framesLeft/ num_play_channels; i++ )
81 *wptr++ = playdata->
read();
82 if (num_play_channels == 2) {
83 *wptr++ = playdata->
read();
85 for (
size_t chs = 2; chs < num_play_channels; chs++) {
89 for( ; i<framesPerBuffer; i++ )
92 if (num_play_channels == 2) {
96 #ifdef STOP_PLAY_ON_EMPTY_BUFFER
100 finished = paComplete;
102 finished = paContinue;
108 yCDebug(PORTAUDIOPLAYER) <<
"Reading" << framesPerBuffer*2 <<
"bytes from the circular buffer";
110 for( i=0; i<framesPerBuffer; i++ )
112 *wptr++ = playdata->
read();
113 if (num_play_channels == 2) {
114 *wptr++ = playdata->
read();
116 for (
size_t chs = 2; chs < num_play_channels; chs++) {
122 finished = paContinue;
127 yCError(PORTAUDIOPLAYER,
"No read operations requested, aborting");
143 while(this->isStopping()==
false)
147 if(m_playback_enabled)
149 m_err = Pa_IsStreamActive(m_stream);
153 yCError(PORTAUDIOPLAYER) <<
"Unhandled error. Calling abortSound()";
174 m_system_resource(nullptr)
176 memset(&m_outputParameters, 0,
sizeof(PaStreamParameters));
187 if (m_stream !=
nullptr)
189 m_err = Pa_CloseStream(m_stream);
190 if (m_err != paNoError)
192 yCError(PORTAUDIOPLAYER,
"An error occurred while closing the portaudio stream");
193 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err);
194 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err));
204 return (m_err == paNoError);
207 bool PortAudioPlayerDeviceDriver::configureDeviceAndStart()
214 m_err = Pa_Initialize();
215 if (m_err != paNoError)
217 yCError(PORTAUDIOPLAYER,
"portaudio system failed to initialize");
224 m_outputParameters.suggestedLatency = Pa_GetDeviceInfo(m_outputParameters.device)->defaultLowOutputLatency;
225 m_outputParameters.hostApiSpecificStreamInfo =
nullptr;
227 m_err = Pa_OpenStream(
237 if (m_err != paNoError)
239 yCError(PORTAUDIOPLAYER,
"An error occurred while using the portaudio stream");
240 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err);
241 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err));
252 if (config.
check(
"help"))
254 yCInfo(PORTAUDIOPLAYER,
"Some examples:");
255 yCInfo(PORTAUDIOPLAYER,
"yarpdev --device portaudioPlayer --help");
256 yCInfo(PORTAUDIOPLAYER,
"yarpdev --device AudioPlayerWrapper --subdevice portaudioPlayer --start");
261 if (!b) {
return false; }
263 m_device_id = config.
check(
"id",
Value(-1),
"which portaudio index to use (-1=automatic)").asInt32();
269 b = configureDeviceAndStart();
270 return (m_err==paNoError);
278 if(m_err != paNoError )
280 yCError(PORTAUDIOPLAYER,
"An error occurred while using the portaudio stream" );
281 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
282 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
291 bool PortAudioPlayerDeviceDriver::abortSound()
293 yCInfo(PORTAUDIOPLAYER,
"=== Stopping and clearing stream.==="); fflush(stdout);
294 m_err = Pa_StopStream(m_stream );
295 if(m_err != paNoError )
297 yCError(PORTAUDIOPLAYER,
"abortSound: error occurred while stopping the portaudio stream" );
298 yCError(PORTAUDIOPLAYER,
"Error number: %d", m_err );
299 yCError(PORTAUDIOPLAYER,
"Error message: %s", Pa_GetErrorText(m_err ) );
304 return (m_err==paNoError);
309 yCError(PORTAUDIOPLAYER,
"Not yet implemented");
315 while (Pa_IsStreamStopped(m_stream) == 0)
327 AudioPlayerDeviceBase::startPlayback();
328 m_err = Pa_StartStream(m_stream);
330 yCInfo(PORTAUDIOPLAYER) <<
"started playback";
336 AudioPlayerDeviceBase::stopPlayback();
337 m_err = Pa_StopStream(m_stream);
339 yCInfo(PORTAUDIOPLAYER) <<
"stopped playback";
#define DEFAULT_FRAMES_PER_BUFFER
static int bufferIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
bool threadInit() override
Initialization method.
void waitUntilPlaybackStreamIsComplete() override
bool stopPlayback() override
Stop the playback.
bool interruptDeviceAndClose() override
void run() override
Main body of the new thread.
bool setHWGain(double gain) override
Sets the hardware gain of the playback device (if supported by the hardware)
~PortAudioPlayerDeviceDriver() override
PortAudioPlayerDeviceDriver()
bool close() override
Close the DeviceDriver.
bool startPlayback() override
Start the playback.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
void threadRelease() override
Release method.
yarp::dev::CircularAudioBuffer_16t * m_outputBuffer
bool configurePlayerAudioDevice(yarp::os::Searchable &config, std::string device_name)
AudioDeviceDriverSettings m_audioplayer_cfg
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.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
bool stop()
Stop the thread.
bool start()
Start the new thread running.
A single value (typically within a Bottle).
#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.