summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_jack.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-03-05 18:01:40 +0100
committerwm4 <wm4@nowhere>2014-03-05 18:02:41 +0100
commitd268d896d94064ecc980bc3be0c46e975cda7a3d (patch)
treef76a156b86a76c7bc46c3841f20b3822d8cdccea /audio/out/ao_jack.c
parent5b3fd09908d82ff1215c35e32e5cca4c83c6ffb7 (diff)
downloadmpv-d268d896d94064ecc980bc3be0c46e975cda7a3d.tar.bz2
mpv-d268d896d94064ecc980bc3be0c46e975cda7a3d.tar.xz
ao_jack: fix termination on the end of file
The player didn't quit when the end of a file was reached. The reason for this is that jack reported a constant audio delay even when all audio was done playing. Whether that was recognized as EOF by the player depended whether the exact value was higher or lower than the player's threshhold for what it considers no more audio. get_delay() should return amount of time it takes until the last sample written to the audio buffer reaches the speaker. Therefore, we have to track the estimated time when the last sample is done, and subtract it from the calculated latency. Basically, the latency is the only amount of time left in the delay, and it should go towards 0 as audio reaches ths speakers. I'm not sure if this is correct, but at least it solves the problem. One suspicious thing is that we use system time to estimate the end of the audio time. Maybe using jack_frame_time() would be more correct. But apart from this, there doesn't seem to be a better way to handle this.
Diffstat (limited to 'audio/out/ao_jack.c')
-rw-r--r--audio/out/ao_jack.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index f4cb5c475e..72235a2d48 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -60,10 +60,12 @@ struct priv {
int connect;
int autostart;
int stdlayout;
+ int last_chunk;
volatile int paused;
volatile int underrun;
volatile float callback_interval;
volatile float callback_time;
+ volatile float last_ok_time; // last time real audio was played
int num_ports;
struct port_ring ports[MP_NUM_CHANNELS];
@@ -128,11 +130,15 @@ process(jack_nframes_t nframes, void *arg)
underrun = 1;
}
+ float now = mp_time_us() / 1000000.0;
+
if (underrun)
p->underrun = 1;
+ if (!p->underrun)
+ p->last_ok_time = now;
+
if (p->estimate) {
- float now = mp_time_us() / 1000000.0;
float diff = p->callback_time + p->callback_interval - now;
if ((diff > -0.002) && (diff < 0.002))
p->callback_time += p->callback_interval;
@@ -289,14 +295,23 @@ static float get_delay(struct ao *ao)
struct priv *p = ao->priv;
int buffered = mp_ring_buffered(p->ports[0].ring); // could be less
float in_jack = p->jack_latency;
+ float now = mp_time_us() / 1000000.0;
if (p->estimate && p->callback_interval > 0) {
float elapsed = mp_time_us() / 1000000.0 - p->callback_time;
in_jack += p->callback_interval - elapsed;
- if (in_jack < 0)
- in_jack = 0;
}
+ if (p->underrun && !buffered && p->last_chunk) {
+ // Report correct buffer drainage, when our buffer is empty, but jack
+ // and/or the audio device still have some audio to play.
+ // Assumes audio clock goes at about the same speed as the system time.
+ in_jack += p->last_ok_time - now;
+ }
+
+ if (in_jack < 0)
+ in_jack = 0;
+
return (float)buffered / (float)ao->bps + in_jack;
}
@@ -369,6 +384,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
}
p->underrun = 0;
+ p->last_chunk = flags & AOPLAY_FINAL_CHUNK;
return ret / ao->sstride;
}