summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_null.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-05-31 15:00:35 +0200
committerwm4 <wm4@nowhere>2020-06-01 01:08:16 +0200
commitd27ad9654218463694093697e3d09f8983b4ccf3 (patch)
tree54d889bbed1b32b2a702fee6825c66ff6fb60c33 /audio/out/ao_null.c
parentd448dd5bf26408ccced1bd6df8f9eaf62a370c8e (diff)
downloadmpv-d27ad9654218463694093697e3d09f8983b4ccf3.tar.bz2
mpv-d27ad9654218463694093697e3d09f8983b4ccf3.tar.xz
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm, ao_lavc. There are changes to the other AOs too, but that's only about renaming ao_driver.resume to ao_driver.start. ao_openal is broken because I didn't manage to fix it, so it exits with an error message. If you want it, why don't _you_ put effort into it? I see no reason to waste my own precious lifetime over this (I realize the irony). ao_alsa loses the poll() mechanism, but it was mostly broken and didn't really do what it was supposed to. There doesn't seem to be anything in the ALSA API to watch the playback status without polling (unless you want to use raw UNIX signals). No idea if ao_pulse is correct, or whether it's subtly broken now. There is no documentation, so I can't tell what is correct, without reverse engineering the whole project. I recommend using ALSA. This was supposed to be just a simple fix, but somehow it expanded scope like a train wreck. Very high chance of regressions, but probably only for the AOs listed above. The rest you can figure out from reading the diff.
Diffstat (limited to 'audio/out/ao_null.c')
-rw-r--r--audio/out/ao_null.c89
1 files changed, 42 insertions, 47 deletions
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index 07a0d4748c..107dc7e35a 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -40,9 +40,10 @@
struct priv {
bool paused;
double last_time;
- bool playing_final;
float buffered; // samples
int buffersize; // samples
+ bool playing;
+ bool underrun;
int untimed;
float bufferlen; // seconds
@@ -77,8 +78,7 @@ static void drain(struct ao *ao)
if (priv->buffered > 0) {
priv->buffered -= (now - priv->last_time) * ao->samplerate * priv->speed;
if (priv->buffered < 0) {
- if (!priv->playing_final)
- MP_ERR(ao, "buffer underrun\n");
+ priv->underrun = true;
priv->buffered = 0;
}
}
@@ -127,85 +127,81 @@ static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
priv->buffered = 0;
- priv->playing_final = false;
+ priv->underrun = false;
+ priv->playing = false;
}
-// stop playing, keep buffers (for pause)
-static void pause(struct ao *ao)
+static void start(struct ao *ao)
{
struct priv *priv = ao->priv;
- drain(ao);
- priv->paused = true;
-}
-
-// resume playing, after pause()
-static void resume(struct ao *ao)
-{
- struct priv *priv = ao->priv;
+ if (priv->paused)
+ MP_ERR(ao, "illegal state: start() while paused\n");
drain(ao);
priv->paused = false;
priv->last_time = mp_time_sec();
+ priv->playing = true;
}
-static int get_space(struct ao *ao)
+static bool set_pause(struct ao *ao, bool paused)
{
struct priv *priv = ao->priv;
- drain(ao);
- int samples = priv->buffersize - priv->latency - priv->buffered;
- return samples / priv->outburst * priv->outburst;
+ if (!priv->playing)
+ MP_ERR(ao, "illegal state: set_pause() while not playing\n");
+
+ if (priv->paused != paused) {
+
+ drain(ao);
+ priv->paused = paused;
+ if (!priv->paused)
+ priv->last_time = mp_time_sec();
+ }
+
+ return true;
}
-static int play(struct ao *ao, void **data, int samples, int flags)
+static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *priv = ao->priv;
- int accepted;
-
- resume(ao);
if (priv->buffered <= 0)
priv->buffered = priv->latency; // emulate fixed latency
- priv->playing_final = flags & AOPLAY_FINAL_CHUNK;
- if (priv->playing_final) {
- // Last audio chunk - don't round to outburst.
- accepted = MPMIN(priv->buffersize - priv->buffered, samples);
- } else {
- int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst;
- int playbursts = samples / priv->outburst;
- int bursts = playbursts > maxbursts ? maxbursts : playbursts;
- accepted = bursts * priv->outburst;
- }
- priv->buffered += accepted;
- return accepted;
+ priv->buffered += samples;
+ return true;
}
-static double get_delay(struct ao *ao)
+static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
struct priv *priv = ao->priv;
drain(ao);
- // Note how get_delay returns the delay in audio device time (instead of
+ state->free_samples = priv->buffersize - priv->latency - priv->buffered;
+ state->free_samples = state->free_samples / priv->outburst * priv->outburst;
+ state->queued_samples = priv->buffered;
+
+ // Note how get_state returns the delay in audio device time (instead of
// adjusting for speed), since most AOs seem to also do that.
- double delay = priv->buffered;
+ state->delay = priv->buffered;
// Drivers with broken EOF handling usually always report the same device-
// level delay that is additional to the buffer time.
if (priv->broken_eof && priv->buffered < priv->latency)
- delay = priv->latency;
+ state->delay = priv->latency;
- delay /= ao->samplerate;
+ state->delay /= ao->samplerate;
if (priv->broken_delay) { // Report only multiples of outburst
double q = priv->outburst / (double)ao->samplerate;
- if (delay > 0)
- delay = (int)(delay / q) * q;
+ if (state->delay > 0)
+ state->delay = (int)(state->delay / q) * q;
}
- return delay;
+ state->underrun = priv->underrun;
+ priv->underrun = false;
}
#define OPT_BASE_STRUCT struct priv
@@ -216,11 +212,10 @@ const struct ao_driver audio_out_null = {
.init = init,
.uninit = uninit,
.reset = reset,
- .get_space = get_space,
- .play = play,
- .get_delay = get_delay,
- .pause = pause,
- .resume = resume,
+ .get_state = get_state,
+ .set_pause = set_pause,
+ .write = audio_write,
+ .start = start,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.bufferlen = 0.2,