summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-09-15 22:25:01 +0200
committerwm4 <wm4@nowhere>2014-09-15 23:08:19 +0200
commit7c2fb859ab10fa375a38179fd49daac36ab111c8 (patch)
tree8fb801b25a5795fcf0e2fa805ba4f2753dcfeb64 /audio
parentd5b8b5b901fb71030b29f5d41884b53deac9c838 (diff)
downloadmpv-7c2fb859ab10fa375a38179fd49daac36ab111c8.tar.bz2
mpv-7c2fb859ab10fa375a38179fd49daac36ab111c8.tar.xz
ao_oss: don't break playback when device can't be reopened
Apparently NetBSD users want/need this (see issue #1080). In order not to break playback, we need at least to emulate get_delay(). We do this approximately by using the system clock. Also, always close the audio device on reset. Reopen it on play only. If we can't reopen it, don't retry until after the next time reset or resume is called, to avoid spam and unexpectedly "stealing" back the audio device. Also do something about framestepping causing audio desync.
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_oss.c65
1 files changed, 42 insertions, 23 deletions
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 86c04354dd..496259b579 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -39,6 +39,7 @@
#include "config.h"
#include "options/options.h"
#include "common/msg.h"
+#include "osdep/timer.h"
#if HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
@@ -60,11 +61,13 @@
struct priv {
int audio_fd;
- int prepause_space;
+ int prepause_samples;
int oss_mixer_channel;
int audio_delay_method;
int buffersize;
int outburst;
+ bool device_failed;
+ double audio_end;
char *dsp;
char *oss_mixer_device;
@@ -235,6 +238,7 @@ static int device_writable(struct ao *ao)
static void close_device(struct ao *ao)
{
struct priv *p = ao->priv;
+ p->device_failed = false;
if (p->audio_fd == -1)
return;
#if defined(SNDCTL_DSP_RESET)
@@ -501,10 +505,6 @@ static void reset(struct ao *ao)
ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
#else
close_device(ao);
- if (reopen_device(ao, false) < 0) {
- MP_ERR(ao, "Fatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
- return;
- }
#endif
}
@@ -519,19 +519,10 @@ static int get_space(struct ao *ao)
return zz.fragments * zz.fragsize / ao->sstride;
}
- return device_writable(ao) > 0 ? p->outburst / ao->sstride : 0;
-}
+ if (p->audio_fd < 0 || device_writable(ao) > 0)
+ return p->outburst / ao->sstride;
-// stop playing, keep buffers (for pause)
-static void audio_pause(struct ao *ao)
-{
- struct priv *p = ao->priv;
- p->prepause_space = get_space(ao) * ao->sstride;
-#if KEEP_DEVICE
- ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
-#else
- close_device(ao);
-#endif
+ return 0;
}
// plays 'len' samples of 'data'
@@ -543,6 +534,19 @@ static int play(struct ao *ao, void **data, int samples, int flags)
int len = samples * ao->sstride;
if (len == 0)
return len;
+
+ if (p->audio_fd < 0 && !p->device_failed && reopen_device(ao, false) < 0)
+ MP_ERR(ao, "Fatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
+ if (p->audio_fd < 0) {
+ // Let playback continue normally, even with a closed device.
+ p->device_failed = true;
+ double now = mp_time_sec();
+ if (p->audio_end < now)
+ p->audio_end = now;
+ p->audio_end += samples / (double)ao->samplerate;
+ return samples;
+ }
+
if (len > p->outburst || !(flags & AOPLAY_FINAL_CHUNK)) {
len /= p->outburst;
len *= p->outburst;
@@ -555,18 +559,21 @@ static int play(struct ao *ao, void **data, int samples, int flags)
static void audio_resume(struct ao *ao)
{
struct priv *p = ao->priv;
-#if !KEEP_DEVICE
- reset(ao);
-#endif
- int fillframes = get_space(ao) - p->prepause_space / ao->sstride;
- if (fillframes > 0)
- ao_play_silence(ao, fillframes);
+ p->audio_end = 0;
+ if (p->prepause_samples > 0)
+ ao_play_silence(ao, p->prepause_samples);
}
// return: delay in seconds between first and last sample in buffer
static float get_delay(struct ao *ao)
{
struct priv *p = ao->priv;
+ if (p->audio_fd < 0) {
+ double rest = p->audio_end - mp_time_sec();
+ if (rest > 0)
+ return rest;
+ return 0;
+ }
/* Calculate how many bytes/second is sent out */
if (p->audio_delay_method == 2) {
#ifdef SNDCTL_DSP_GETODELAY
@@ -586,6 +593,18 @@ static float get_delay(struct ao *ao)
return ((float)p->buffersize) / (float)ao->bps;
}
+// stop playing, keep buffers (for pause)
+static void audio_pause(struct ao *ao)
+{
+ struct priv *p = ao->priv;
+ p->prepause_samples = get_delay(ao) * ao->samplerate;
+#if KEEP_DEVICE
+ ioctl(p->audio_fd, SNDCTL_DSP_RESET, NULL);
+#else
+ close_device(ao);
+#endif
+}
+
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_oss = {