summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/out/ao.c7
-rw-r--r--audio/out/ao_alsa.c1
-rw-r--r--audio/out/ao_lavc.c4
-rw-r--r--audio/out/ao_null.c2
-rw-r--r--audio/out/ao_openal.c1
-rw-r--r--audio/out/ao_oss.c3
-rw-r--r--audio/out/ao_sndio.c2
-rw-r--r--audio/out/internal.h8
-rw-r--r--audio/out/push.c15
9 files changed, 39 insertions, 4 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index a2a001c50c..b699b64c5a 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -194,6 +194,8 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
ao->stream_silence = flags & AO_INIT_STREAM_SILENCE;
+ ao->period_size = 1;
+
int r = ao->driver->init(ao);
if (r < 0) {
// Silly exception for coreaudio spdif redirection
@@ -209,6 +211,11 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
goto fail;
}
+ if (ao->period_size < 1) {
+ MP_ERR(ao, "Invalid period size set.\n");
+ goto fail;
+ }
+
ao->sstride = af_fmt_to_bytes(ao->format);
ao->num_planes = 1;
if (af_fmt_is_planar(ao->format)) {
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index c0efdaff40..b0099011dc 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -840,6 +840,7 @@ static int init_device(struct ao *ao, int mode)
MP_VERBOSE(ao, "period size: %d samples\n", (int)p->outburst);
ao->device_buffer = p->buffersize;
+ ao->period_size = p->outburst;
return 0;
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index 619f4fe72a..f247cba12e 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -160,6 +160,8 @@ static int init(struct ao *ao)
ao->untimed = true;
+ ao->period_size = ac->aframesize * ac->framecount;
+
if (ao->channels.num > AV_NUM_DATA_POINTERS)
goto fail;
@@ -203,7 +205,7 @@ static void uninit(struct ao *ao)
ac->shutdown = true;
}
-// return: how many bytes can be played without blocking
+// return: how many samples can be played without blocking
static int get_space(struct ao *ao)
{
struct priv *ac = ao->priv;
diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c
index 4b07634d22..29d88d4670 100644
--- a/audio/out/ao_null.c
+++ b/audio/out/ao_null.c
@@ -108,6 +108,8 @@ static int init(struct ao *ao)
priv->last_time = mp_time_sec();
+ ao->period_size = priv->outburst;
+
return 0;
}
diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c
index 9d22abb38e..715ffddceb 100644
--- a/audio/out/ao_openal.c
+++ b/audio/out/ao_openal.c
@@ -214,6 +214,7 @@ static int init(struct ao *ao)
}
p->chunk_size = CHUNK_SAMPLES * af_fmt_to_bytes(ao->format);
+ ao->period_size = CHUNK_SAMPLES;
return 0;
err_out:
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 1478d1400e..1edf55a095 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -394,7 +394,8 @@ static int reopen_device(struct ao *ao, bool allow_format_changes)
}
}
- p->outburst -= p->outburst % (channels.num * af_fmt_to_bytes(format)); // round down
+ ao->period_size = channels.num * af_fmt_to_bytes(format);
+ p->outburst -= p->outburst % ao->period_size; // round down
return 0;
diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c
index d9ac4ef7e4..20490fe0a3 100644
--- a/audio/out/ao_sndio.c
+++ b/audio/out/ao_sndio.c
@@ -195,6 +195,8 @@ static int init(struct ao *ao)
if (!p->pfd)
goto error;
+ ao->period_size = p->par.round;
+
return 0;
error:
diff --git a/audio/out/internal.h b/audio/out/internal.h
index a4be59982a..0c59ce973e 100644
--- a/audio/out/internal.h
+++ b/audio/out/internal.h
@@ -48,6 +48,14 @@ struct ao {
int init_flags; // AO_INIT_* flags
bool stream_silence; // if audio inactive, just play silence
+ // Set by the driver on init. This is typically the period size, and the
+ // smallest unit the driver will accept in one piece (although if
+ // AOPLAY_FINAL_CHUNK is set, the driver must accept everything).
+ // This value is in complete samples (i.e. 1 for stereo means 1 sample
+ // for both channels each).
+ // Used for push based API only.
+ int period_size;
+
// The device as selected by the user, usually using ao_device_desc.name
// from an entry from the list returned by driver->list_devices. If the
// default device should be used, this is set to NULL.
diff --git a/audio/out/push.c b/audio/out/push.c
index a722d19ea2..c271fc0cdc 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -285,6 +285,8 @@ static void ao_play_data(struct ao *ao)
int space = ao->driver->get_space(ao);
bool play_silence = p->paused || (ao->stream_silence && !p->still_playing);
space = MPMAX(space, 0);
+ if (space % ao->period_size)
+ MP_ERR(ao, "Audio device reports unaligned available buffer size.\n");
struct mp_audio data;
if (play_silence) {
ao_get_silence(ao, &data, space);
@@ -295,16 +297,25 @@ static void ao_play_data(struct ao *ao)
if (data.samples > space)
data.samples = space;
int flags = 0;
- if (p->final_chunk && data.samples == max)
+ if (p->final_chunk && data.samples == max) {
flags |= AOPLAY_FINAL_CHUNK;
+ } else {
+ data.samples = data.samples / ao->period_size * ao->period_size;
+ }
MP_STATS(ao, "start ao fill");
int r = 0;
if (data.samples)
r = ao->driver->play(ao, data.planes, data.samples, flags);
MP_STATS(ao, "end ao fill");
if (r > data.samples) {
- MP_WARN(ao, "Audio device returned non-sense value.\n");
+ MP_ERR(ao, "Audio device returned non-sense value.\n");
r = data.samples;
+ } else if (r < 0) {
+ MP_ERR(ao, "Error writing audio to device.\n");
+ } else if (r != data.samples) {
+ MP_ERR(ao, "Audio device returned broken buffer state (sent %d samples, "
+ "got %d samples, %d period%s)!\n", data.samples, r,
+ ao->period_size, flags & AOPLAY_FINAL_CHUNK ? " final" : "");
}
r = MPMAX(r, 0);
// Probably can't copy the rest of the buffer due to period alignment.