00001 #include "PANetworkPlayer.hxx"
00002
00003 #include "PushFlowControl.hxx"
00004 #include "XMLStorage.hxx"
00005 #include <pthread.h>
00006
00007
00008 namespace CLAM
00009 {
00010
00011
00012 int PANetworkPlayer::ProcessCallback (const void *inputBuffers, void *outputBuffers,
00013 unsigned long framesPerBuffer,
00014 const PaStreamCallbackTimeInfo* timeInfo,
00015 PaStreamCallbackFlags statusFlags,
00016 void *userData)
00017 {
00018 if (statusFlags)
00019 {
00020 if (statusFlags & paOutputUnderflow)
00021 std::cerr << "Portaudio backend: Output Underflow" << std::endl;
00022 if (statusFlags & paInputUnderflow)
00023 std::cerr << "Portaudio backend: Input Underflow" << std::endl;
00024 if (statusFlags & paOutputOverflow)
00025 std::cerr << "Portaudio backend: Output Overflow" << std::endl;
00026 if (statusFlags & paInputOverflow)
00027 std::cerr << "Portaudio backend: Input Overflow" << std::endl;
00028 if (statusFlags & paPrimingOutput)
00029 std::cerr << "Portaudio backend: Priming Output" << std::endl;
00030 }
00031 PANetworkPlayer* player=(PANetworkPlayer*)userData;
00032
00033 player->Do(inputBuffers, outputBuffers, framesPerBuffer);
00034
00035 return 0;
00036 }
00037
00038
00039 void displayPADevices()
00040 {
00041 int howManiApis = Pa_GetHostApiCount();
00042 int defaultApi = Pa_GetDefaultHostApi();
00043 std::cout << "Default API " << defaultApi << std::endl;
00044 for (int api=0; api<howManiApis; api++)
00045 {
00046 const PaHostApiInfo * apiInfo = Pa_GetHostApiInfo( api );
00047 std::cout
00048 << (api==defaultApi?"* ":" ")
00049 << apiInfo->name
00050 << " (" << api << ")"
00051 << std::endl;
00052 for (int device=0; device<apiInfo->deviceCount; device++)
00053 {
00054 int fullDevice = Pa_HostApiDeviceIndexToDeviceIndex(api, device);
00055 const PaDeviceInfo * deviceInfo = Pa_GetDeviceInfo(fullDevice);
00056 std::cout << "\t"
00057 << " (" << fullDevice << "/" << device << ") "
00058 << (fullDevice == Pa_GetDefaultInputDevice()? "*<": " ")
00059 << (fullDevice == Pa_GetDefaultOutputDevice()? "*>": " ")
00060 << (fullDevice == apiInfo->defaultInputDevice?"*<":" ")
00061 << (fullDevice == apiInfo->defaultOutputDevice?"*>":" ")
00062 << deviceInfo->name
00063 << " Inputs: " << deviceInfo->maxInputChannels
00064 << " Outputs: " << deviceInfo->maxOutputChannels
00065 << std::endl;
00066 }
00067 }
00068 }
00069
00070 PANetworkPlayer::PANetworkPlayer()
00071 : mPreferredBufferSize(paFramesPerBufferUnspecified)
00072 , mSamplingRate(48000)
00073 , mPortAudioStream(0)
00074 , mError(paNoError)
00075
00076 {
00077 }
00078
00079 PANetworkPlayer::~PANetworkPlayer()
00080 {
00081 Stop();
00082 }
00083
00084 void PANetworkPlayer::Start()
00085 {
00086 if ( !IsStopped() )
00087 return;
00088 if (CheckPaError(Pa_Initialize())) return;
00089 displayPADevices();
00090
00091 CollectSourcesAndSinks();
00092
00093 int nInChannels = _sources.size();
00094 int nOutChannels = _sinks.size();
00095
00096 PaHostApiTypeId apiTryList[] = {
00097 paDirectSound,
00098 paMME,
00099 paASIO,
00100 paSoundManager,
00101 paCoreAudio,
00102 paALSA,
00103 paAL,
00104 paBeOS,
00105 paWDMKS,
00106 paJACK,
00107
00108
00109 paOSS,
00110 paInDevelopment
00111 };
00112
00113
00114 const PaHostApiInfo * apiInfo = 0;
00115 for (unsigned i=0; apiTryList[i]!=paInDevelopment; i++)
00116 {
00117 PaHostApiIndex apiIndex = Pa_HostApiTypeIdToHostApiIndex(apiTryList[i]);
00118 std::cerr << apiIndex << std::endl;
00119 if (apiIndex<0) continue;
00120 apiInfo = Pa_GetHostApiInfo( apiIndex );
00121 std::cerr << "Portaudio Chosen API: " << apiInfo->name << " " << apiIndex << std::endl;
00122 break;
00123 }
00124 CLAM_ASSERT(apiInfo, "PortAudio: No API available.");
00125
00126 PaStreamParameters inputParameters;
00127 PaStreamParameters * inParams = 0;
00128 if (nInChannels)
00129 {
00130 inputParameters.device = apiInfo->defaultInputDevice;
00131 if ( inputParameters.device == paNoDevice )
00132 {
00133 mErrorMessage = "No free default input device";
00134 std::cerr << "PortAudio Error: " << mErrorMessage << std::endl;
00135 return;
00136 }
00137 const PaDeviceInfo * info = Pa_GetDeviceInfo( inputParameters.device );
00138 std::cerr << "PortAudio: Chosen Input: " << info->name << std::endl;
00139 if (nInChannels > Pa_GetDeviceInfo( inputParameters.device )->maxInputChannels)
00140 {
00141 mErrorMessage = "Too many input channels for the default device";
00142 std::cerr << "PortAudio Error: " << mErrorMessage << std::endl;
00143 return;
00144 }
00145 inputParameters.channelCount = nInChannels;
00146 inputParameters.sampleFormat = paFloat32 | paNonInterleaved ;
00147 inputParameters.suggestedLatency = info->defaultLowOutputLatency;
00148 inputParameters.hostApiSpecificStreamInfo = NULL;
00149 inParams = &inputParameters;
00150 }
00151
00152 PaStreamParameters outputParameters;
00153 PaStreamParameters * outParams = 0;
00154 if (nOutChannels)
00155 {
00156 outputParameters.device = apiInfo->defaultOutputDevice;
00157 if ( outputParameters.device == paNoDevice )
00158 {
00159 mErrorMessage = "No free default output device";
00160 std::cerr << "PortAudio Error: " << mErrorMessage << std::endl;
00161 return;
00162 }
00163 const PaDeviceInfo * info = Pa_GetDeviceInfo( outputParameters.device );
00164 std::cerr << "PortAudio: Chosen Output: " << info->name << std::endl;
00165 if (nOutChannels > Pa_GetDeviceInfo( outputParameters.device )->maxOutputChannels)
00166 {
00167 mErrorMessage = "Too many output channels for the default device";
00168 std::cerr << "PortAudio Error: " << mErrorMessage << std::endl;
00169 return;
00170 }
00171 outputParameters.channelCount = nOutChannels;
00172 outputParameters.sampleFormat = paFloat32 | paNonInterleaved ;
00173 outputParameters.suggestedLatency = info->defaultLowOutputLatency;
00174 outputParameters.hostApiSpecificStreamInfo = NULL;
00175 outParams = &outputParameters;
00176 }
00177 CLAM_ASSERT(!mPortAudioStream, "Portaudio: Previous stream not closed");
00178 if (CheckPaError(
00179 Pa_OpenStream(
00180 &mPortAudioStream,
00181 inParams,
00182 outParams,
00183 double(mSamplingRate),
00184 mPreferredBufferSize,
00185 paClipOff,
00186 ProcessCallback,
00187 this )
00188 ))
00189 {
00190 mErrorMessage = "Audio i/o devices requirements not fullfilled";
00191 return;
00192 }
00193 SetStopped(false);
00194 const PaStreamInfo * streamInfo = Pa_GetStreamInfo(mPortAudioStream);
00195 std::cout << "Sample rate: " << streamInfo->sampleRate << std::endl;
00196 std::cout << "Input latency: " << streamInfo->inputLatency << std::endl;
00197 std::cout << "Output latency: " << streamInfo->outputLatency << std::endl;
00198
00199 mNeedsPriority=true;
00200 Pa_StartStream( mPortAudioStream );
00201 }
00202
00203 void PANetworkPlayer::Stop()
00204 {
00205 if ( IsStopped() )
00206 return;
00207 if ( mPortAudioStream )
00208 {
00209 Pa_StopStream( mPortAudioStream );
00210 CheckPaError( Pa_CloseStream( mPortAudioStream ) );
00211 mPortAudioStream=0;
00212 }
00213 SetStopped(true);
00214 Pa_Terminate();
00215 }
00216
00217 bool PANetworkPlayer::IsWorking() const
00218 {
00219 return mError==paNoError;
00220 }
00221
00222 std::string PANetworkPlayer::NonWorkingReason() const
00223 {
00224 return mErrorMessage;
00225 }
00226
00227
00228 bool PANetworkPlayer::CheckPaError(PaError result)
00229 {
00230 mError = result;
00231 if( result == paNoError ) return false;
00232 mErrorMessage = Pa_GetErrorText(mError);
00233 std::cerr
00234 << "PortAudio Error #" << result << ": "
00235 << Pa_GetErrorText( result ) << std::endl;
00236 return true;
00237 }
00238
00239 void PANetworkPlayer::Do(const void *inputBuffers, void *outputBuffers,
00240 unsigned long framesPerBuffer)
00241 {
00242 if (IsStopped()) return;
00243 if (mNeedsPriority)
00244 {
00245 mNeedsPriority = false;
00246 #ifdef TODO__was_WIN32
00247 BOOL res;
00248 DWORD err;
00249
00250 res = SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS );
00251 err = GetLastError();
00252 res = SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL );
00253 err = GetLastError();
00254 #else
00255 struct sched_param sched_param;
00256 int policy;
00257
00258 if (pthread_getschedparam(pthread_self(), &policy, &sched_param) < 0)
00259 std::cerr << "Scheduler getparam failed..." << std::endl;
00260 sched_param.sched_priority = sched_get_priority_max(SCHED_RR)-1;
00261 if (!pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param))
00262 std::cerr << "Scheduler set to Round Robin with priority "<< sched_param.sched_priority << std::endl;
00263 #endif
00264 }
00265 DoInPorts( (float**) inputBuffers, framesPerBuffer);
00266 DoOutPorts( (float**) outputBuffers, framesPerBuffer);
00267 GetNetwork().Do();
00268 }
00269
00270 void PANetworkPlayer::DoInPorts(float** input, unsigned long nframes)
00271 {
00272 int i=0;
00273 for ( AudioSources::iterator it=_sources.begin(); it!=_sources.end(); it++ )
00274 {
00275 (*it)->SetExternalBuffer( input[i++], nframes );
00276 }
00277 }
00278
00279 void PANetworkPlayer::DoOutPorts(float** output, unsigned long nframes)
00280 {
00281 int i=0;
00282 for (AudioSinks::iterator it=_sinks.begin(); it!=_sinks.end(); it++)
00283 {
00284 (*it)->SetExternalBuffer(output[i++], nframes);
00285 }
00286 }
00287
00288 }
00289