24 #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
65 unsigned long framesPerBuffer,
66 const PaStreamCallbackTimeInfo* timeInfo,
67 PaStreamCallbackFlags statusFlags,
73 int num_rec_channels = dataBuffers->numRecChannels;
74 int num_play_channels = dataBuffers->numPlayChannels;
75 int finished = paComplete;
77 if (dataBuffers->canRec)
79 const auto* rptr = (
const SAMPLE*)inputBuffer;
80 unsigned int framesToCalc;
90 if( framesLeft/ num_rec_channels < framesPerBuffer )
92 framesToCalc = framesLeft/ num_rec_channels;
93 #ifdef STOP_REC_ON_EMPTY_BUFFER
97 finished = paComplete;
99 finished = paContinue;
104 framesToCalc = framesPerBuffer;
107 finished = paContinue;
110 if( inputBuffer ==
nullptr )
112 for( i=0; i<framesToCalc; i++ )
115 if(num_rec_channels == 2 ) recdata->
write(0);
120 yCTrace(PORTAUDIO) <<
"Writing" << framesToCalc*2*2 <<
"bytes in the circular buffer";
121 for( i=0; i<framesToCalc; i++ )
123 recdata->
write(*rptr++);
124 if(num_rec_channels == 2 ) recdata->
write(*rptr++);
131 if (dataBuffers->canPlay)
133 auto* wptr = (
SAMPLE*)outputBuffer;
143 if( framesLeft/ num_play_channels < framesPerBuffer )
146 for( i=0; i<framesLeft/ num_play_channels; i++ )
148 *wptr++ = playdata->
read();
149 if( num_play_channels == 2 ) *wptr++ = playdata->
read();
150 for (
int chs=2; chs<num_play_channels; chs++) playdata->
read();
152 for( ; i<framesPerBuffer; i++ )
155 if(num_play_channels == 2 ) *wptr++ = 0;
157 #ifdef STOP_PLAY_ON_EMPTY_BUFFER
161 finished = paComplete;
163 finished = paContinue;
169 yCDebug(PORTAUDIO) <<
"Reading" << framesPerBuffer*2 <<
"bytes from the circular buffer";
171 for( i=0; i<framesPerBuffer; i++ )
173 *wptr++ = playdata->
read();
174 if( num_play_channels == 2 ) *wptr++ = playdata->
read();
175 for (
int chs=2; chs<num_play_channels; chs++) playdata->
read();
179 finished = paContinue;
185 yCError(PORTAUDIO,
"No read/write operations requested, aborting");
194 m_system_resource(nullptr),
195 m_numPlaybackChannels(0),
196 m_numRecordChannels(0),
199 m_getSoundIsNotBlocking(true),
200 renderMode(RENDER_APPEND)
202 memset(&inputParameters, 0,
sizeof(PaStreamParameters));
203 memset(&outputParameters, 0,
sizeof(PaStreamParameters));
216 m_driverConfig.
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();
228 if (config.
check(
"loopback",
"if present, send audio read from microphone immediately back to speaker"))
230 yCError(PORTAUDIO,
"loopback not yet implemented");
234 if (config.
check(
"render_mode_append"))
238 if (config.
check(
"render_mode_immediate"))
248 int rate = config.
rate;
278 if (dataBuffers.
recData==
nullptr)
280 if (wantRead) dataBuffers.
canRec =
true;
281 if (wantWrite) dataBuffers.
canPlay =
true;
283 err = Pa_Initialize();
284 if( err != paNoError )
286 yCError(PORTAUDIO,
"portaudio system failed to initialize");
290 inputParameters.device = (deviceNumber==-1)?Pa_GetDefaultInputDevice():deviceNumber;
291 yCInfo(PORTAUDIO,
"Device number %d", inputParameters.device);
294 if ((Pa_GetDeviceInfo( inputParameters.device ))!=
nullptr) {
295 inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
297 inputParameters.hostApiSpecificStreamInfo =
nullptr;
299 outputParameters.device = (deviceNumber==-1)?Pa_GetDefaultOutputDevice():deviceNumber;
302 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
303 outputParameters.hostApiSpecificStreamInfo =
nullptr;
307 wantRead?(&inputParameters):
nullptr,
308 wantWrite?(&outputParameters):
nullptr,
315 if( err != paNoError )
317 yCError(PORTAUDIO,
"An error occurred while using the portaudio stream");
318 yCError(PORTAUDIO,
"Error number: %d", err);
319 yCError(PORTAUDIO,
"Error message: %s", Pa_GetErrorText(err));
326 return (err==paNoError);
329 void streamThread::handleError()
332 if( err != paNoError )
334 yCError(PORTAUDIO,
"An error occurred while using the portaudio stream");
335 yCError(PORTAUDIO,
"Error number: %d", err);
336 yCError(PORTAUDIO,
"Error message: %s\n", Pa_GetErrorText(err));
345 if( err != paNoError )
347 yCError(PORTAUDIO,
"An error occurred while using the portaudio stream");
348 yCError(PORTAUDIO,
"Error number: %d", err);
349 yCError(PORTAUDIO,
"Error message: %s", Pa_GetErrorText(err));
356 if (stream !=
nullptr)
358 err = Pa_CloseStream( stream );
359 if( err != paNoError )
361 yCError(PORTAUDIO,
"An error occurred while closing the portaudio stream");
362 yCError(PORTAUDIO,
"Error number: %d", err);
363 yCError(PORTAUDIO,
"Error message: %s", Pa_GetErrorText(err));
367 if (this->dataBuffers.
playData !=
nullptr)
370 this->dataBuffers.
playData =
nullptr;
372 if (this->dataBuffers.
recData !=
nullptr)
374 delete this->dataBuffers.
recData;
375 this->dataBuffers.
recData =
nullptr;
378 return (err==paNoError);
384 err = Pa_StartStream( stream );
392 err = Pa_StopStream( stream );
404 size_t buff_size = 0;
405 int buff_size_wdt = 0;
410 if (buff_size_wdt > 100)
414 yCError(PORTAUDIO) <<
"PortAudioDeviceDriver::getSound() Buffer size is still zero after 100 iterations, returning";
419 yCDebug(PORTAUDIO) <<
"PortAudioDeviceDriver::getSound() Buffer size is " << buff_size <<
"/" << this->numSamples <<
" after 100 iterations";
422 yCError(PORTAUDIO) <<
"PortAudioDeviceDriver::getSound() is in not-blocking mode, returning";
430 while (buff_size < this->numSamples);
440 for (
size_t i=0; i<this->numSamples; i++)
451 yCInfo(PORTAUDIO,
"=== Stopping and clearing stream.==="); fflush(stdout);
452 err = Pa_StopStream( stream );
453 if( err != paNoError )
455 yCError(PORTAUDIO,
"abortSound: error occurred while stopping the portaudio stream" );
456 yCError(PORTAUDIO,
"Error number: %d", err );
457 yCError(PORTAUDIO,
"Error message: %s", Pa_GetErrorText( err ) );
462 return (err==paNoError);
484 err = Pa_StartStream(
stream );
485 if( err != paNoError ) {handleError();
return;}
487 while( ( err = Pa_IsStreamActive(
stream ) ) == 1 )
493 yCDebug(PORTAUDIO) <<
"The playback stream has been stopped";
501 err = Pa_StopStream(
stream );
513 while( ( err = Pa_IsStreamActive(
stream ) ) == 1 )
520 yCDebug(PORTAUDIO) <<
"The recording stream has been stopped";
543 for (
size_t i=0; i<num_samples; i++)
544 for (
size_t j=0; j<num_channels; j++)
559 while (Pa_IsStreamStopped(stream )==0)
565 yCInfo(PORTAUDIO,
"***** audio driver configuration changed, resetting");
567 chans <<
"channels, " << freq <<
" Hz";
574 yCError(PORTAUDIO,
"error occurred during audio driver reconfiguration, aborting");
593 for (
size_t i=0; i<num_samples; i++)
594 for (
size_t j=0; j<num_channels; j++)