CLAM-Development
1.1
|
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 // paWASAPI, 00108 // paAudioScienceHPI, 00109 paOSS, 00110 paInDevelopment 00111 }; 00112 // int defaultApi = Pa_GetDefaultHostApi(); 00113 // const PaHostApiInfo * apiInfo = Pa_GetHostApiInfo( defaultApi ); 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 //Create configuration for input&output and then register the stream 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 ; /* 32 bit floating point output, having non-interleaved samples*/ 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 ; /* 32 bit floating point output, having non-interleaved samples */ 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, /* we won't output out of range samples so don't bother clipping them */ 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 } //end namespace CLAM 00289