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);