summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/ao.rst6
-rw-r--r--audio/out/ao_null.c69
2 files changed, 56 insertions, 19 deletions
diff --git a/DOCS/man/en/ao.rst b/DOCS/man/en/ao.rst
index c5b1b37fb3..5b1d710b40 100644
--- a/DOCS/man/en/ao.rst
+++ b/DOCS/man/en/ao.rst
@@ -157,6 +157,12 @@ Available audio output drivers are:
decoding will go as fast as possible, instead of timing it to the
system clock.
+ ``buffer``
+ Simulated buffer length in seconds.
+
+ ``outburst``
+ Simulated chunk size in samples.
+
``pcm``
Raw PCM/WAVE file writer audio output
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index ec15f145f1..4153a13e44 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -18,6 +18,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+/*
+ * Note: this does much more than just ignoring audio output. It simulates
+ * (to some degree) an ideal AO.
+ */
+
#include <stdio.h>
#include <stdlib.h>
@@ -26,18 +31,24 @@
#include "config.h"
#include "osdep/timer.h"
#include "mpvcore/m_option.h"
+#include "mpvcore/mp_msg.h"
#include "audio/format.h"
#include "ao.h"
struct priv {
bool paused;
double last_time;
- // All values are in samples
- float buffered;
- int buffersize;
- int outburst;
+ bool playing_final;
+ float buffered; // samples
+ int buffersize; // samples
int untimed;
+ float bufferlen; // seconds
+
+ // Minimal unit of audio samples that can be written at once. If play() is
+ // called with sizes not aligned to this, a rounded size will be returned.
+ // (This is not needed by the AO API, but many AOs behave this way.)
+ int outburst; // samples
};
static void drain(struct ao *ao)
@@ -53,9 +64,14 @@ static void drain(struct ao *ao)
return;
double now = mp_time_sec();
- priv->buffered -= (now - priv->last_time) * ao->samplerate;
- if (priv->buffered < 0)
- priv->buffered = 0;
+ if (priv->buffered > 0) {
+ priv->buffered -= (now - priv->last_time) * ao->samplerate;
+ if (priv->buffered < 0) {
+ if (!priv->playing_final)
+ MP_ERR(ao, "buffer underrun\n");
+ priv->buffered = 0;
+ }
+ }
priv->last_time = now;
}
@@ -70,13 +86,8 @@ static int init(struct ao *ao)
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
- // Minimal unit of audio samples that can be written at once. If play() is
- // called with sizes not aligned to this, a rounded size will be returned.
- // (This is not needed by the AO API, but many AOs behave this way.)
- priv->outburst = 256;
-
- // A "buffer" for about 0.2 seconds of audio
- int bursts = (int)(ao->samplerate * 0.2 + 1) / priv->outburst;
+ // A "buffer" for this many seconds of audio
+ int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst;
priv->buffersize = priv->outburst * bursts;
priv->last_time = mp_time_sec();
@@ -87,6 +98,9 @@ static int init(struct ao *ao)
// close audio device
static void uninit(struct ao *ao, bool cut_audio)
{
+ struct priv *priv = ao->priv;
+ if (!cut_audio && !priv->paused)
+ mp_sleep_us(1000.0 * 1000.0 * priv->buffered / ao->samplerate);
}
// stop playing and empty buffers (for seeking/pause)
@@ -94,6 +108,7 @@ static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
priv->buffered = 0;
+ priv->playing_final = false;
}
// stop playing, keep buffers (for pause)
@@ -101,6 +116,7 @@ static void pause(struct ao *ao)
{
struct priv *priv = ao->priv;
+ drain(ao);
priv->paused = true;
}
@@ -125,13 +141,22 @@ static int get_space(struct ao *ao)
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *priv = ao->priv;
+ int accepted;
resume(ao);
- int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst;
- int playbursts = samples / priv->outburst;
- int bursts = playbursts > maxbursts ? maxbursts : playbursts;
- priv->buffered += bursts * priv->outburst;
- return bursts * priv->outburst;
+
+ 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;
}
static float get_delay(struct ao *ao)
@@ -156,8 +181,14 @@ const struct ao_driver audio_out_null = {
.pause = pause,
.resume = resume,
.priv_size = sizeof(struct priv),
+ .priv_defaults = &(const struct priv) {
+ .bufferlen = 200,
+ .outburst = 256,
+ },
.options = (const struct m_option[]) {
OPT_FLAG("untimed", untimed, 0),
+ OPT_FLOATRANGE("buffer", bufferlen, 0, 0, 100),
+ OPT_INTRANGE("outburst", outburst, 0, 1, 100000),
{0}
},
};