PANetworkPlayer.cxx

Go to the documentation of this file.
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 

Generated on Tue Aug 12 22:33:43 2008 for CLAM by  doxygen 1.5.5