Skip to content

Commit d5c66e3

Browse files
committed
alsa: simplify probing for default latency
Use a method that is less prone to failure. Also change GropeDevice() to ProbeDeviceDefaults(). Fixes #1145
1 parent b0fe9de commit d5c66e3

1 file changed

Lines changed: 40 additions & 29 deletions

File tree

src/hostapi/alsa/pa_linux_alsa.c

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ _PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_max);
163163
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size);
164164
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_min);
165165
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_max);
166+
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_min);
166167
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_max);
167168
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_min);
168169
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_max);
@@ -448,6 +449,7 @@ static int PaAlsa_LoadLibrary()
448449
_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size);
449450
_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min);
450451
_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max);
452+
_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_min);
451453
_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max);
452454
_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min);
453455
_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max);
@@ -534,6 +536,7 @@ static int PaAlsa_LoadLibrary()
534536
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max);
535537
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min);
536538
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max);
539+
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_min);
537540
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max);
538541
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min);
539542
_PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max);
@@ -844,18 +847,22 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
844847
* traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
845848
* and a suitable result returned. The device is closed before returning.
846849
*/
847-
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
850+
static PaError ProbeDeviceDefaults( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
848851
PaAlsaDeviceInfo* devInfo )
849852
{
850853
PaError result = paNoError;
851854
snd_pcm_hw_params_t *hwParams;
852-
snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames;
853855
unsigned int minChans = 0;
854856
unsigned int maxChans = 0;
855857
int* minChannels, * maxChannels;
858+
snd_pcm_uframes_t lowBufferFrames = 0;
859+
snd_pcm_uframes_t highBufferFrames = 0;
860+
int ret = 0;
856861
double * defaultLowLatency, * defaultHighLatency;
857862
double defaultSr = devInfo->baseDeviceInfo.defaultSampleRate;
858863
unsigned int approximateSampleRate = 0;
864+
const int kLowBufferFrames = 512;
865+
const int kHighBufferFrames = 2048;
859866

860867
assert( pcm );
861868

@@ -947,32 +954,35 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in
947954
PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
948955
}
949956

950-
/* TWEAKME:
951-
* Giving values for default min and max latency is not straightforward.
952-
* * for low latency, we want to give the lowest value that will work reliably.
953-
* This varies based on the sound card, kernel, CPU, etc. Better to give
954-
* sub-optimal latency than to give a number too low and cause dropouts.
955-
* * for high latency we want to give a large enough value that dropouts are basically impossible.
956-
* This doesn't really require as much tweaking, since providing too large a number will
957-
* just cause us to select the nearest setting that will work at stream config time.
957+
/*
958+
* Choose a reasonable low and high latency based on the min and max buffer size.
958959
*/
959-
/* Try low latency values, (sometimes the buffer & period that result are larger) */
960-
alsaBufferFrames = 512;
961-
alsaPeriodFrames = 128;
962-
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
963-
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, NULL ), paUnanticipatedHostError );
964-
*defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
965-
966-
/* Base the high latency case on values four times larger */
967-
alsaBufferFrames = 2048;
968-
alsaPeriodFrames = 512;
969-
/* Have to reset hwParams, to set new buffer size; need to also set sample rate again */
970-
ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
971-
ENSURE_( SetApproximateSampleRate( pcm, hwParams, &approximateSampleRate ), paUnanticipatedHostError );
972-
defaultSr = (double) approximateSampleRate;
973-
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
974-
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, NULL ), paUnanticipatedHostError );
975-
*defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
960+
ret = alsa_snd_pcm_hw_params_get_buffer_size_min( hwParams, &lowBufferFrames );
961+
if (ret) {
962+
printf( "%s: alsa_snd_pcm_hw_params_get_buffer_size_min() returned %d !\n", __FUNCTION__, ret );
963+
lowBufferFrames = kLowBufferFrames;
964+
}
965+
ret = alsa_snd_pcm_hw_params_get_buffer_size_max( hwParams, &highBufferFrames );
966+
if (ret) {
967+
printf( "%s: alsa_snd_pcm_hw_params_get_buffer_size_max() returned %d !\n", __FUNCTION__, ret );
968+
highBufferFrames = kHighBufferFrames;
969+
}
970+
printf( "%s: lowBufferFrames = %u, highBufferFrames = %u\n",
971+
__FUNCTION__, lowBufferFrames, highBufferFrames );
972+
973+
/* Clip to ensure optimal low value. */
974+
if (lowBufferFrames < kLowBufferFrames) lowBufferFrames = kLowBufferFrames;
975+
/* Base the high latency case on values four times larger. */
976+
const snd_pcm_uframes_t lowTimesN = lowBufferFrames * 4;
977+
/* Clip to ensure optimal high value. */
978+
if (highBufferFrames > lowTimesN) highBufferFrames = lowTimesN;
979+
if (highBufferFrames > kHighBufferFrames) highBufferFrames = kHighBufferFrames;
980+
981+
/* Assume period is 1/4 the buffer so it will normally be 3/4 full. */
982+
*defaultLowLatency = (double) ((lowBufferFrames * 3) / 4) / defaultSr;
983+
*defaultHighLatency = (double) ((highBufferFrames * 3) / 4) / defaultSr;
984+
printf( "%s: defaultLowLatency = %f, defaultHighLatency = %f\n",
985+
__FUNCTION__, *defaultLowLatency, *defaultHighLatency );
976986

977987
*minChannels = (int)minChans;
978988
*maxChannels = (int)maxChans;
@@ -1209,7 +1219,7 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d
12091219
if( deviceHwInfo->hasCapture &&
12101220
OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 )
12111221
{
1212-
if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
1222+
if( ProbeDeviceDefaults( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
12131223
{
12141224
/* Error */
12151225
PA_DEBUG(( "%s: Failed groping %s for capture\n", __FUNCTION__, deviceHwInfo->alsaName ));
@@ -1221,7 +1231,7 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d
12211231
if( deviceHwInfo->hasPlayback &&
12221232
OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 )
12231233
{
1224-
if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
1234+
if( ProbeDeviceDefaults( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
12251235
{
12261236
/* Error */
12271237
PA_DEBUG(( "%s: Failed groping %s for playback\n", __FUNCTION__, deviceHwInfo->alsaName ));
@@ -1869,6 +1879,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const
18691879
result = paUnanticipatedHostError;
18701880
}
18711881

1882+
printf( "%s: ret = %d\n", __FUNCTION__, ret );
18721883
ENSURE_( ret, result );
18731884
}
18741885
}

0 commit comments

Comments
 (0)