/[pcsx2_0.9.7]/trunk/3rdparty/portaudio/src/hostapi/alsa/pa_linux_alsa.c
ViewVC logotype

Diff of /trunk/3rdparty/portaudio/src/hostapi/alsa/pa_linux_alsa.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 31 by william, Tue Sep 7 03:24:11 2010 UTC revision 62 by william, Tue Sep 7 11:08:22 2010 UTC
# Line 122  typedef struct Line 122  typedef struct
122      int userInterleaved, hostInterleaved;      int userInterleaved, hostInterleaved;
123      int canMmap;      int canMmap;
124      void *nonMmapBuffer;      void *nonMmapBuffer;
125        unsigned int nonMmapBufferSize;
126      PaDeviceIndex device;     /* Keep the device index */      PaDeviceIndex device;     /* Keep the device index */
127    
128      snd_pcm_t *pcm;      snd_pcm_t *pcm;
# Line 809  static PaError BuildDeviceList( PaAlsaHo Line 810  static PaError BuildDeviceList( PaAlsaHo
810    
811              if( predefined )              if( predefined )
812              {              {
813                  hwDevInfos[numDeviceNames - 1].hasPlayback =                  hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback;
814                      predefined->hasPlayback;                  hwDevInfos[numDeviceNames - 1].hasCapture = predefined->hasCapture;
                 hwDevInfos[numDeviceNames - 1].hasCapture =  
                     predefined->hasCapture;  
815              }              }
816              else              else
817              {              {
# Line 1191  static PaError PaAlsaStreamComponent_Ini Line 1190  static PaError PaAlsaStreamComponent_Ini
1190      self->streamDir = streamDir;      self->streamDir = streamDir;
1191      self->canMmap = 0;      self->canMmap = 0;
1192      self->nonMmapBuffer = NULL;      self->nonMmapBuffer = NULL;
1193        self->nonMmapBufferSize = 0;
1194    
1195      if( !callbackMode && !self->userInterleaved )      if( !callbackMode && !self->userInterleaved )
1196      {      {
# Line 1233  static PaError PaAlsaStreamComponent_Ini Line 1233  static PaError PaAlsaStreamComponent_Ini
1233    
1234      PaError result = paNoError;      PaError result = paNoError;
1235      snd_pcm_access_t accessMode, alternateAccessMode;      snd_pcm_access_t accessMode, alternateAccessMode;
     snd_pcm_access_t rwAccessMode, alternateRwAccessMode;  
1236      int dir = 0;      int dir = 0;
1237      snd_pcm_t *pcm = self->pcm;      snd_pcm_t *pcm = self->pcm;
1238      double sr = *sampleRate;      double sr = *sampleRate;
# Line 1253  static PaError PaAlsaStreamComponent_Ini Line 1252  static PaError PaAlsaStreamComponent_Ini
1252      if( self->userInterleaved )      if( self->userInterleaved )
1253      {      {
1254          accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;          accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
         rwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;  
1255          alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;          alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1256          alternateRwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;  
1257            /* test if MMAP supported */
1258            self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
1259                            snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
1260            if (!self->canMmap)
1261            {
1262                accessMode          = SND_PCM_ACCESS_RW_INTERLEAVED;
1263                alternateAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1264        }
1265      }      }
1266      else      else
1267      {      {
1268          accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;          accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
         rwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;  
1269          alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;          alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1270          alternateRwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;  
1271            /* test if MMAP supported */
1272            self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
1273                            snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
1274            if (!self->canMmap)
1275            {
1276                accessMode          = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1277                alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
1278        }
1279      }      }
1280        PA_DEBUG(("%s: device can MMAP: %s\n", __FUNCTION__, (self->canMmap ? "YES" : "NO")));
1281    
1282      /* If requested access mode fails, try alternate mode */      /* If requested access mode fails, try alternate mode */
     self->canMmap = 1;  
1283      if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )      if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
1284      {      {
         if( snd_pcm_hw_params_set_access( pcm, hwParams, rwAccessMode ) >= 0 )  
             self->canMmap = 0;  
         else  
         {  
             if( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ) < 0 )  
             {  
1285                  int err = 0;                  int err = 0;
1286                  if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateRwAccessMode )) >= 0)          if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0)
                     self->canMmap = 0;  
                 else  
1287                  {                  {
1288                      result = paUnanticipatedHostError;                      result = paUnanticipatedHostError;
1289                      PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );                      PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
1290                      goto error;                      goto error;
1291                  }                  }
             }  
1292              /* Flip mode */              /* Flip mode */
1293              self->hostInterleaved = !self->userInterleaved;              self->hostInterleaved = !self->userInterleaved;
1294          }          }
     }  
1295    
1296      ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );      ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
1297    
# Line 2028  static PaError CloseStream( PaStream* s Line 2032  static PaError CloseStream( PaStream* s
2032      PaError result = paNoError;      PaError result = paNoError;
2033      PaAlsaStream *stream = (PaAlsaStream*)s;      PaAlsaStream *stream = (PaAlsaStream*)s;
2034    
2035            free(stream->playback.nonMmapBuffer);
2036            free(stream->capture.nonMmapBuffer);
2037    
2038      PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );      PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2039      PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );      PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
2040    
# Line 2400  static PaError PaAlsaStream_HandleXrun( Line 2407  static PaError PaAlsaStream_HandleXrun(
2407      snd_pcm_status_t *st;      snd_pcm_status_t *st;
2408      PaTime now = PaUtil_GetTime();      PaTime now = PaUtil_GetTime();
2409      snd_timestamp_t t;      snd_timestamp_t t;
2410      int errplayback = 0, errcapture = 0;      int restartAlsa = 0; /* do not restart Alsa by default */
2411    
2412      snd_pcm_status_alloca( &st );      snd_pcm_status_alloca( &st );
2413    
# Line 2411  static PaError PaAlsaStream_HandleXrun( Line 2418  static PaError PaAlsaStream_HandleXrun(
2418          {          {
2419              snd_pcm_status_get_trigger_tstamp( st, &t );              snd_pcm_status_get_trigger_tstamp( st, &t );
2420              self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);              self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2421              errplayback = snd_pcm_recover( self->playback.pcm, -EPIPE, 0 );  
2422                if (!self->playback.canMmap)
2423                {
2424                    if (snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0)
2425                    {
2426                        PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
2427                        ++ restartAlsa; /* did not manage to recover */
2428            }
2429        }
2430                else
2431                    ++ restartAlsa; /* always restart MMAPed device */
2432          }          }
2433      }      }
2434      if( self->capture.pcm )      if( self->capture.pcm )
# Line 2421  static PaError PaAlsaStream_HandleXrun( Line 2438  static PaError PaAlsaStream_HandleXrun(
2438          {          {
2439              snd_pcm_status_get_trigger_tstamp( st, &t );              snd_pcm_status_get_trigger_tstamp( st, &t );
2440              self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);              self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2441              errcapture = snd_pcm_recover( self->capture.pcm, -EPIPE, 0 );  
2442                if (!self->capture.canMmap)
2443                {
2444                    if (snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0)
2445                    {
2446                        PA_DEBUG(( "%s: [capture] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
2447                        ++ restartAlsa; /* did not manage to recover */
2448            }
2449        }
2450                else
2451                    ++ restartAlsa; /* always restart MMAPed device */
2452          }          }
2453      }      }
2454    
2455      if( errplayback || errcapture )      if( restartAlsa )
2456        {
2457            PA_DEBUG(( "%s: restarting Alsa to recover from XRUN\n", __FUNCTION__ ));
2458          PA_ENSURE( AlsaRestart( self ) );          PA_ENSURE( AlsaRestart( self ) );
2459        }
2460    
2461  end:  end:
2462      return result;      return result;
# Line 2609  static PaError PaAlsaStreamComponent_End Line 2639  static PaError PaAlsaStreamComponent_End
2639          res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );          res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
2640      else      else
2641      {      {
2642            /* using realloc for optimisation
2643          free( self->nonMmapBuffer );          free( self->nonMmapBuffer );
2644          self->nonMmapBuffer = NULL;          self->nonMmapBuffer = NULL;
2645            */
2646      }      }
2647    
2648      if( res == -EPIPE || res == -ESTRPIPE )      if( res == -EPIPE || res == -ESTRPIPE )
# Line 2784  static PaError PaAlsaStreamComponent_End Line 2816  static PaError PaAlsaStreamComponent_End
2816              *xrun = 1;              *xrun = 1;
2817          }          }
2818          else          else
2819            if( revents & POLLHUP )
2820            {
2821                *xrun = 1;
2822                PA_DEBUG(( "%s: revents has POLLHUP, processing as XRUN\n", __FUNCTION__ ));
2823            }
2824            else
2825              self->ready = 1;              self->ready = 1;
2826    
2827          *shouldPoll = 0;          *shouldPoll = 0;
# Line 2865  static PaError PaAlsaStream_WaitForFrame Line 2903  static PaError PaAlsaStream_WaitForFrame
2903      PaError result = paNoError;      PaError result = paNoError;
2904      int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;      int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
2905      int pollTimeout = self->pollTimeout;      int pollTimeout = self->pollTimeout;
2906      int xrun = 0;      int xrun = 0, timeouts = 0;
2907        int pollResults;
2908    
2909      assert( self );      assert( self );
2910      assert( framesAvail );      assert( framesAvail );
# Line 2912  static PaError PaAlsaStream_WaitForFrame Line 2951  static PaError PaAlsaStream_WaitForFrame
2951              totalFds += self->playback.nfds;              totalFds += self->playback.nfds;
2952          }          }
2953    
2954          if( poll( self->pfds, totalFds, pollTimeout ) < 0 )          pollResults = poll( self->pfds, totalFds, pollTimeout );
2955    
2956            if( pollResults < 0 )
2957          {          {
2958              /*  XXX: Depend on preprocessor condition? */              /*  XXX: Depend on preprocessor condition? */
2959              if( errno == EINTR )              if( errno == EINTR )
2960              {              {
2961                  /* gdb */                  /* gdb */
2962                    Pa_Sleep( 1 ); /* avoid hot loop */
2963                  continue;                  continue;
2964              }              }
2965    
2966              /* TODO: Add macro for checking system calls */              /* TODO: Add macro for checking system calls */
2967              PA_ENSURE( paInternalError );              PA_ENSURE( paInternalError );
2968          }          }
2969            else
2970            if (pollResults == 0)
2971            {
2972    
2973               /* Suspended, paused or failed device can provide 0 poll results. To avoid deadloop in such situation
2974                * we simply run counter 'timeouts' which detects 0 poll result and accumulates. As soon as 64 timouts
2975                * are achieved we simply fail function with paTimedOut to notify waiting methods that device is not capable
2976                * of providing audio data anymore and needs some corresponding recovery action.
2977                * Note that 'timeouts' is reset to 0 if poll() managed to return non 0 results.
2978                */
2979    
2980                /*PA_DEBUG(( "%s: poll == 0 results, timed out, %d times left\n", __FUNCTION__, 64 - timeouts ));*/
2981    
2982                ++ timeouts;
2983                if (timeouts > 1) /* sometimes device times out, but normally once, so we do not sleep any time */
2984                {
2985                    Pa_Sleep( 1 ); /* avoid hot loop */
2986                }
2987                /* not else ! */
2988                if (timeouts >= 64) /* audio device not working, shall return error to notify waiters */
2989                {
2990                    PA_DEBUG(( "%s: poll timed out, returning error\n", __FUNCTION__, timeouts ));
2991                    PA_ENSURE( paTimedOut );
2992                }
2993            }
2994            else
2995            if (pollResults > 0)
2996            {
2997                /* reset timouts counter */
2998                timeouts = 0;
2999    
3000          /* check the return status of our pfds */          /* check the return status of our pfds */
3001          if( pollCapture )          if( pollCapture )
# Line 2938  static PaError PaAlsaStream_WaitForFrame Line 3010  static PaError PaAlsaStream_WaitForFrame
3010          {          {
3011              break;              break;
3012          }          }
3013            }
3014    
3015          /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.          /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
3016           * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will           * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
# Line 3040  static PaError PaAlsaStreamComponent_Reg Line 3113  static PaError PaAlsaStreamComponent_Reg
3113      }      }
3114      else      else
3115      {      {
3116            /* using realloc for optimisation
3117          free( self->nonMmapBuffer );          free( self->nonMmapBuffer );
3118          self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );          self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
3119            */
3120            unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
3121            if (bufferSize > self->nonMmapBufferSize)
3122            {
3123                self->nonMmapBuffer = realloc(self->nonMmapBuffer, (self->nonMmapBufferSize = bufferSize));
3124                if (!self->nonMmapBuffer)
3125                {
3126                    result = paInsufficientMemory;
3127                    goto error;
3128        }
3129            }
3130      }      }
3131    
3132      if( self->hostInterleaved )      if( self->hostInterleaved )
# Line 3100  static PaError PaAlsaStreamComponent_Reg Line 3185  static PaError PaAlsaStreamComponent_Reg
3185          {          {
3186              *xrun = 1;              *xrun = 1;
3187              *numFrames = 0;              *numFrames = 0;
3188    
3189                /* using realloc for optimisation
3190              free( self->nonMmapBuffer );              free( self->nonMmapBuffer );
3191              self->nonMmapBuffer = NULL;              self->nonMmapBuffer = NULL;
3192                */
3193          }          }
3194      }      }
3195    

Legend:
Removed from v.31  
changed lines
  Added in v.62

  ViewVC Help
Powered by ViewVC 1.1.22