summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-01-06 19:28:08 +0100
committerwm4 <wm4@nowhere>2013-01-06 19:28:08 +0100
commit9b3bf76d27c9cd87685aee4cb6652ef7071237b3 (patch)
treed4855cf4d61ba86b1f4ebab3f746c66f70b9c299
parent67ee79283b5e3f1fb9e0bdad96922b0bd431b365 (diff)
downloadmpv-9b3bf76d27c9cd87685aee4cb6652ef7071237b3.tar.bz2
mpv-9b3bf76d27c9cd87685aee4cb6652ef7071237b3.tar.xz
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.
-rw-r--r--audio/out/ao_alsa.c8
1 files changed, 8 insertions, 0 deletions
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;