From 9b3bf76d27c9cd87685aee4cb6652ef7071237b3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 6 Jan 2013 19:28:08 +0100 Subject: ao_alsa: do not call snd_pcm_delay() when paused This causes trouble when a hw device is used: pcm_hw.c:514:(snd_pcm_hw_delay) SNDRV_PCM_IOCTL_DELAY failed (-77): File descriptor in bad state when running mpv test.mkv --ao=alsa:device=iec958,alsa and pausing during playback. Historically, mplayer usually did not call snd_pcm_delay() (which is called by get_delay()) while paused, so this problem never showed up. But at least mpv has changes that cause get_delay() to be called when updating the status line (see commit 3f949cf). It's possible that calling snd_pcm_delay() is not always legal when the audio is paused, and at least fails with the error message mentioned above is the device is a hardware device. Change get_delay() to return the last delay before the audio was paused. The intention is to get a continuous playback status display, even when pausing or frame stepping, otherwise we could just return the audio buffer fill status in get_delay() or even just 0 when paused. --- audio/out/ao_alsa.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 8e23ddefd2..366b912b76 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -69,6 +69,7 @@ static size_t bytes_per_sample; static int alsa_can_pause; static snd_pcm_sframes_t prepause_frames; +static float delay_before_pause; #define ALSA_DEVICE_SIZE 256 @@ -354,6 +355,7 @@ static int init(int rate_hz, int channels, int format, int flags) mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version()); prepause_frames = 0; + delay_before_pause = 0; snd_lib_error_set_handler(alsa_error_handler); @@ -703,6 +705,7 @@ static void audio_pause(void) int err; if (alsa_can_pause) { + delay_before_pause = get_delay(); if ((err = snd_pcm_pause(alsa_handler, 1)) < 0) { mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm pause error: %s\n", snd_strerror(err)); @@ -713,6 +716,7 @@ static void audio_pause(void) if (snd_pcm_delay(alsa_handler, &prepause_frames) < 0 || prepause_frames < 0) prepause_frames = 0; + delay_before_pause = prepause_frames / (float)ao_data.samplerate; if ((err = snd_pcm_drop(alsa_handler)) < 0) { @@ -757,6 +761,7 @@ static void reset(void) int err; prepause_frames = 0; + delay_before_pause = 0; if ((err = snd_pcm_drop(alsa_handler)) < 0) { mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err)); @@ -847,6 +852,9 @@ static float get_delay(void) if (alsa_handler) { snd_pcm_sframes_t delay; + if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_PAUSED) + return delay_before_pause; + if (snd_pcm_delay(alsa_handler, &delay) < 0) return 0; -- cgit v1.2.3