From: Micha Nelissen * fix allocation of buffer, buffer_size is number of frames * use default 16 bit depth (some hardware has small buffers, 16/24 bit difference is very small) XXX: Without this patch madplay produces noices while playing back on a system with 2.6.28, which it works for 2.6.27 without patch. Confirmed on PXA270 platforms. We might test this issue on more platforms. Signed-off-by: FIXME --- audio_alsa.c | 81 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 32 deletions(-) Index: audio_alsa.c =================================================================== --- audio_alsa.c.orig +++ audio_alsa.c @@ -28,31 +28,30 @@ #include -#define ALSA_PCM_OLD_HW_PARAMS_API -#define ALSA_PCM_OLD_SW_PARAMS_API #include #include #include "audio.h" -char *buf = NULL; -int paused = 0; +#define BUFFER_TIME_MAX 500000 -int rate = -1; -int channels = -1; -int bitdepth = -1; -int sample_size = -1; - -int buffer_time = 500000; -int period_time = 100000; -char *defaultdev = "plughw:0,0"; +unsigned char *buf = NULL; +int paused = 0; + +unsigned int rate = 0; +unsigned int channels = -1; +unsigned int bitdepth = -1; +unsigned int sample_size = -1; + +unsigned int buffer_time; +unsigned int period_time; +char *defaultdev = "plughw:0,0"; snd_pcm_hw_params_t *alsa_hwparams; snd_pcm_sw_params_t *alsa_swparams; -snd_pcm_sframes_t buffer_size; -snd_pcm_sframes_t period_size; +snd_pcm_uframes_t buffer_size; snd_pcm_format_t alsa_format = -1; snd_pcm_access_t alsa_access = SND_PCM_ACCESS_MMAP_INTERLEAVED; @@ -66,7 +65,7 @@ int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) { - int err, dir; + int err; /* choose all parameters */ err = snd_pcm_hw_params_any(handle,params); @@ -74,6 +73,14 @@ int set_hwparams(snd_pcm_t *handle, printf("Access type not available for playback: %s\n", snd_strerror(err)); return err; } + + /* set the access type */ + err = snd_pcm_hw_params_set_access(handle, params, alsa_access); + if (err < 0) { + printf("Sample format not available for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, alsa_format); if (err < 0) { @@ -87,29 +94,43 @@ int set_hwparams(snd_pcm_t *handle, return err; } /* set the stream rate */ - err = snd_pcm_hw_params_set_rate_near(handle, params, rate, 0); + err = snd_pcm_hw_params_set_rate(handle, params, rate, 0); + if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return err; } - if (err != rate) { - printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); - return -EINVAL; + err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, NULL); + if (err < 0) { + printf("Unable to retrieve buffer time: %s\n", snd_strerror(err)); + return err; } + if (buffer_time > BUFFER_TIME_MAX) + buffer_time = BUFFER_TIME_MAX; + /* set buffer time */ - err = snd_pcm_hw_params_set_buffer_time_near(handle, params, buffer_time, &dir); + err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); if (err < 0) { printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); return err; } - buffer_size = snd_pcm_hw_params_get_buffer_size(params); + if (period_time * 4 > buffer_time) + period_time = buffer_time / 4; + /* set period time */ - err = snd_pcm_hw_params_set_period_time_near(handle, params, period_time, &dir); + err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, NULL); + if (err < 0) { printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); return err; } - period_size = snd_pcm_hw_params_get_period_size(params, &dir); + /* retrieve buffer size */ + err = snd_pcm_hw_params_get_buffer_size(params, &buffer_size); + if (err < 0) { + printf("Unable to retrieve buffer size: %s\n", snd_strerror(err)); + return err; + } + /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { @@ -123,6 +144,8 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *params) { + unsigned int start_threshold; + int err; /* get current swparams */ @@ -137,12 +160,6 @@ int set_swparams(snd_pcm_t *handle, printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); return err; } - /* allow transfer when at least period_size samples can be processed */ - err = snd_pcm_sw_params_set_avail_min(handle, params, period_size); - if (err < 0) { - printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); - return err; - } /* align all transfers to 1 samples */ err = snd_pcm_sw_params_set_xfer_align(handle, params, 1); if (err < 0) { @@ -190,7 +207,7 @@ int config(struct audio_config *config) rate = config->speed; if ( bitdepth == 0 ) - config->precision = bitdepth = 32; + config->precision = bitdepth = 16; switch (bitdepth) { @@ -241,7 +258,7 @@ int config(struct audio_config *config) return -1; } - buf = malloc(buffer_size); + buf = malloc(buffer_size * sample_size); if (buf == NULL) { audio_error="unable to allocate output buffer table"; return -1; @@ -279,7 +296,7 @@ static int play(struct audio_play *play) { int err, len; - char *ptr; + unsigned char *ptr; ptr = buf; len = play->nsamples;