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