PANetworkPlayer.cxx

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