From 24c1f46353213e3392b542a6c3655bcd215e7c63 Mon Sep 17 00:00:00 2001
From: Eric Wong <normalperson@yhbt.net>
Date: Mon, 24 Jul 2006 01:38:51 +0000
Subject: audioOutput_alsa: better period_size auto-configuration

We'll try setting an initial value of 50ms, and halve it each
time snd_pcm_hw_params fails with -EPIPE.

This way we'll can use a larger (50ms) period_size whenever a device
supports it, and automatically pick smaller ones if we can't set
larger ones.

This removes the calculation borrowed from libao (svn) as well.

Other minor things:
"Alsa" => "ALSA" in error messages
_US appended to *_TIME constants so we won't get confused
(shank's request)

git-svn-id: https://svn.musicpd.org/mpd/trunk@4438 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 src/audioOutputs/audioOutput_alsa.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

(limited to 'src/audioOutputs')

diff --git a/src/audioOutputs/audioOutput_alsa.c b/src/audioOutputs/audioOutput_alsa.c
index 603abcee4..c129e2d6e 100644
--- a/src/audioOutputs/audioOutput_alsa.c
+++ b/src/audioOutputs/audioOutput_alsa.c
@@ -25,12 +25,12 @@
 #define ALSA_PCM_NEW_HW_PARAMS_API
 #define ALSA_PCM_NEW_SW_PARAMS_API
 
-#define MPD_ALSA_BUFFER_TIME 500000
+#define MPD_ALSA_BUFFER_TIME_US 500000
 /* the default period time of xmms is 50 ms, so let's use that as well.
  * a user can tweak this parameter via the "period_time" config parameter.
  */
-#define MPD_ALSA_PERIOD_TIME 50000
-#define MPD_ALSA_SAMPLE_XFER 256
+#define MPD_ALSA_PERIOD_TIME_US 50000
+#define MPD_ALSA_RETRY_NR 5
 
 #include "../conf.h"
 #include "../log.h"
@@ -65,8 +65,8 @@ static AlsaData *newAlsaData(void)
 	ret->pcmHandle = NULL;
 	ret->writei = snd_pcm_writei;
 	ret->useMmap = 0;
-	ret->buffer_time = MPD_ALSA_BUFFER_TIME;
-	ret->period_time = MPD_ALSA_PERIOD_TIME;
+	ret->buffer_time = MPD_ALSA_BUFFER_TIME_US;
+	ret->period_time = MPD_ALSA_PERIOD_TIME_US;
 
 	return ret;
 }
@@ -139,7 +139,9 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 	snd_pcm_uframes_t alsa_buffer_size;
 	snd_pcm_uframes_t alsa_period_size;
 	int err;
-	char *cmd = NULL;
+	const char *cmd = NULL;
+	unsigned int period_time;
+	int retry = MPD_ALSA_RETRY_NR;
 
 	switch (audioFormat->bits) {
 	case 8:
@@ -155,7 +157,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 		bitformat = SND_PCM_FORMAT_S32;
 		break;
 	default:
-		ERROR("Alsa device \"%s\" doesn't support %i bit audio\n",
+		ERROR("ALSA device \"%s\" doesn't support %i bit audio\n",
 		      ad->device, audioFormat->bits);
 		return -1;
 	}
@@ -173,6 +175,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 	if (err < 0)
 		goto error;
 
+configure_hw:
 	/* configure HW params */
 	snd_pcm_hw_params_alloca(&hwparams);
 
@@ -204,7 +207,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 
 	err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
 	if (err < 0) {
-		ERROR("Alsa device \"%s\" does not support %i bit audio: "
+		ERROR("ALSA device \"%s\" does not support %i bit audio: "
 		      "%s\n", ad->device, (int)bitformat, snd_strerror(-err));
 		goto fail;
 	}
@@ -212,7 +215,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 	err = snd_pcm_hw_params_set_channels_near(ad->pcmHandle, hwparams,
 						  &channels);
 	if (err < 0) {
-		ERROR("Alsa device \"%s\" does not support %i channels: "
+		ERROR("ALSA device \"%s\" does not support %i channels: "
 		      "%s\n", ad->device, (int)audioFormat->channels,
 		      snd_strerror(-err));
 		goto fail;
@@ -222,7 +225,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 	err = snd_pcm_hw_params_set_rate_near(ad->pcmHandle, hwparams,
 					      &sampleRate, NULL);
 	if (err < 0 || sampleRate == 0) {
-		ERROR("Alsa device \"%s\" does not support %i Hz audio\n",
+		ERROR("ALSA device \"%s\" does not support %i Hz audio\n",
 		      ad->device, (int)audioFormat->sampleRate);
 		goto fail;
 	}
@@ -234,8 +237,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 	if (err < 0)
 		goto error;
 
-	if (!ad->period_time && sampleRate > 0)
-		ad->period_time = 1000000 * MPD_ALSA_SAMPLE_XFER / sampleRate;
+	period_time = ad->period_time;
 	cmd = "snd_pcm_hw_params_set_period_time_near";
 	err = snd_pcm_hw_params_set_period_time_near(ad->pcmHandle, hwparams,
 						     &ad->period_time, NULL);
@@ -244,8 +246,13 @@ static int alsa_openDevice(AudioOutput * audioOutput)
 
 	cmd = "snd_pcm_hw_params";
 	err = snd_pcm_hw_params(ad->pcmHandle, hwparams);
-	if (err < 0)
+	if (err == -EPIPE && --retry > 0) {
+		ad->period_time = period_time >> 1;
+		goto configure_hw;
+	} else if (err < 0)
 		goto error;
+	if (retry != MPD_ALSA_RETRY_NR)
+		DEBUG("ALSA period_time set to %d\n", ad->period_time);
 
 	cmd = "snd_pcm_hw_params_get_buffer_size";
 	err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
-- 
cgit v1.2.3