alsa:
- fixed latency setting dependence on user buffer size, now it is completely independent and user is able to set lowest possible/audible latency (approx. 3-4ms) - fixed fixed min. latency for non-MMAPed devices, they do behave similar to MMAPed devices now without a limitation
This commit is contained in:
parent
d2568e4ae7
commit
c8414a679e
1 changed files with 68 additions and 165 deletions
|
|
@ -1257,6 +1257,10 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
|
|||
/* test if MMAP supported */
|
||||
self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
|
||||
snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
|
||||
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO")));
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO")));
|
||||
|
||||
if (!self->canMmap)
|
||||
{
|
||||
accessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||
|
|
@ -1271,12 +1275,17 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
|
|||
/* test if MMAP supported */
|
||||
self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
|
||||
snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
|
||||
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO")));
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO")));
|
||||
|
||||
if (!self->canMmap)
|
||||
{
|
||||
accessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
|
||||
alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||
}
|
||||
}
|
||||
|
||||
PA_DEBUG(("%s: device can MMAP: %s\n", __FUNCTION__, (self->canMmap ? "YES" : "NO")));
|
||||
|
||||
/* If requested access mode fails, try alternate mode */
|
||||
|
|
@ -1478,59 +1487,14 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer;
|
||||
int dir = 0;
|
||||
|
||||
{
|
||||
snd_pcm_uframes_t tmp;
|
||||
snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp );
|
||||
bufferSize = PA_MAX( bufferSize, tmp );
|
||||
snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp );
|
||||
bufferSize = PA_MIN( bufferSize, tmp );
|
||||
}
|
||||
PA_DEBUG(( "%s: frames per user-buffer = %lu\n", __FUNCTION__, framesPerUserBuffer ));
|
||||
PA_DEBUG(( "%s: suggested latency = %f\n", __FUNCTION__, params->suggestedLatency ));
|
||||
PA_DEBUG(( "%s: suggested host buffer size = %lu\n", __FUNCTION__, bufferSize ));
|
||||
|
||||
assert( bufferSize > 0 );
|
||||
|
||||
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
|
||||
{
|
||||
/* Preferably the host buffer size should be a multiple of the user buffer size */
|
||||
|
||||
if( bufferSize > framesPerUserBuffer )
|
||||
{
|
||||
snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;
|
||||
if( remainder > framesPerUserBuffer / 2. )
|
||||
bufferSize += framesPerUserBuffer - remainder;
|
||||
else
|
||||
bufferSize -= remainder;
|
||||
|
||||
assert( bufferSize % framesPerUserBuffer == 0 );
|
||||
}
|
||||
else if( framesPerUserBuffer % bufferSize != 0 )
|
||||
{
|
||||
/* Find a good compromise between user specified latency and buffer size */
|
||||
if( bufferSize > framesPerUserBuffer * .75 )
|
||||
{
|
||||
bufferSize = framesPerUserBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
snd_pcm_uframes_t newSz = framesPerUserBuffer;
|
||||
while( newSz / 2 >= bufferSize )
|
||||
{
|
||||
if( framesPerUserBuffer % (newSz / 2) != 0 )
|
||||
{
|
||||
/* No use dividing any further */
|
||||
break;
|
||||
}
|
||||
newSz /= 2;
|
||||
}
|
||||
bufferSize = newSz;
|
||||
}
|
||||
|
||||
assert( framesPerUserBuffer % bufferSize == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Using the base number of periods, we try to approximate the suggested latency (+1 period),
|
||||
finding a combination of period/buffer size which best fits these constraints */
|
||||
{
|
||||
#define ALIGN_BWD(v,align) (((v) - ((align) ? (v) % (align) : 0)))
|
||||
#define ALIGN_FWD(v,align) (((v) + (align - ((align) ? (v) % (align) : 0))))
|
||||
#define HOST_BUF_ALIGN 16
|
||||
{
|
||||
unsigned numPeriods = numPeriods_, maxPeriods = 0;
|
||||
/* It may be that the device only supports 2 periods for instance */
|
||||
dir = 0;
|
||||
|
|
@ -1538,69 +1502,12 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
assert( maxPeriods > 1 );
|
||||
numPeriods = PA_MIN( maxPeriods, numPeriods );
|
||||
|
||||
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
|
||||
{
|
||||
/* Try to get a power-of-two of the user buffer size. */
|
||||
framesPerHostBuffer = framesPerUserBuffer;
|
||||
if( framesPerHostBuffer < bufferSize )
|
||||
{
|
||||
while( bufferSize / framesPerHostBuffer > numPeriods )
|
||||
{
|
||||
framesPerHostBuffer *= 2;
|
||||
}
|
||||
/* One extra period is preferrable to one less (should be more robust) */
|
||||
if( bufferSize / framesPerHostBuffer < numPeriods )
|
||||
{
|
||||
framesPerHostBuffer /= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( bufferSize / framesPerHostBuffer < numPeriods )
|
||||
{
|
||||
if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 )
|
||||
{
|
||||
/* Can't be divided any further */
|
||||
break;
|
||||
}
|
||||
framesPerHostBuffer /= 2;
|
||||
}
|
||||
}
|
||||
framesPerHostBuffer = ALIGN_FWD((bufferSize / numPeriods), HOST_BUF_ALIGN);
|
||||
}
|
||||
#undef ALIGN_BWD
|
||||
#undef ALIGN_FWD
|
||||
#undef HOST_BUF_ALIGN
|
||||
|
||||
if( framesPerHostBuffer < framesPerUserBuffer )
|
||||
{
|
||||
assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
|
||||
{
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
|
||||
framesPerHostBuffer *= 2;
|
||||
else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
|
||||
framesPerHostBuffer /= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
|
||||
{
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
|
||||
framesPerHostBuffer += framesPerUserBuffer;
|
||||
else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
|
||||
framesPerHostBuffer -= framesPerUserBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
framesPerHostBuffer = bufferSize / numPeriods;
|
||||
}
|
||||
}
|
||||
|
||||
/* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
|
||||
if( !self->canMmap && framesPerHostBuffer < 2048 )
|
||||
framesPerHostBuffer = 2048;
|
||||
|
||||
assert( framesPerHostBuffer > 0 );
|
||||
{
|
||||
snd_pcm_uframes_t min = 0, max = 0;
|
||||
ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
|
||||
|
|
@ -1619,6 +1526,10 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
framesPerHostBuffer = max;
|
||||
}
|
||||
|
||||
PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min ));
|
||||
PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max ));
|
||||
PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer ));
|
||||
|
||||
assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );
|
||||
dir = 0;
|
||||
ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ),
|
||||
|
|
@ -1629,6 +1540,8 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
*accurate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set result */
|
||||
self->framesPerBuffer = framesPerHostBuffer;
|
||||
|
||||
error:
|
||||
|
|
@ -2032,9 +1945,6 @@ static PaError CloseStream( PaStream* s )
|
|||
PaError result = paNoError;
|
||||
PaAlsaStream *stream = (PaAlsaStream*)s;
|
||||
|
||||
free(stream->playback.nonMmapBuffer);
|
||||
free(stream->capture.nonMmapBuffer);
|
||||
|
||||
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
|
||||
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
|
||||
|
||||
|
|
@ -3115,11 +3025,7 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
}
|
||||
else
|
||||
{
|
||||
/* using realloc for optimisation
|
||||
free( self->nonMmapBuffer );
|
||||
self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
|
||||
*/
|
||||
unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, *numFrames );
|
||||
if (bufferSize > self->nonMmapBufferSize)
|
||||
{
|
||||
self->nonMmapBuffer = realloc(self->nonMmapBuffer, (self->nonMmapBufferSize = bufferSize));
|
||||
|
|
@ -3146,20 +3052,22 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
else
|
||||
{
|
||||
if( self->canMmap )
|
||||
{
|
||||
for( i = 0; i < self->numUserChannels; ++i )
|
||||
{
|
||||
area = areas + i;
|
||||
buffer = ExtractAddress( area, self->offset );
|
||||
setChannel( bp, i, buffer, 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
|
||||
buffer = self->nonMmapBuffer;
|
||||
for( i = 0; i < self->numUserChannels; ++i )
|
||||
{
|
||||
setChannel( bp, i, buffer, 1 );
|
||||
buffer += bufsize;
|
||||
buffer += buf_per_ch_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3173,13 +3081,13 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
else
|
||||
{
|
||||
void *bufs[self->numHostChannels];
|
||||
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
|
||||
unsigned char *buffer = self->nonMmapBuffer;
|
||||
int i;
|
||||
for( i = 0; i < self->numHostChannels; ++i )
|
||||
{
|
||||
bufs[i] = buffer;
|
||||
buffer += bufsize;
|
||||
buffer += buf_per_ch_size;
|
||||
}
|
||||
res = snd_pcm_readn( self->pcm, bufs, *numFrames );
|
||||
}
|
||||
|
|
@ -3187,11 +3095,6 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
{
|
||||
*xrun = 1;
|
||||
*numFrames = 0;
|
||||
|
||||
/* using realloc for optimisation
|
||||
free( self->nonMmapBuffer );
|
||||
self->nonMmapBuffer = NULL;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue