diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/out/ao.c | 7 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 1 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 4 | ||||
-rw-r--r-- | audio/out/ao_null.c | 2 | ||||
-rw-r--r-- | audio/out/ao_openal.c | 1 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 3 | ||||
-rw-r--r-- | audio/out/ao_sndio.c | 2 | ||||
-rw-r--r-- | audio/out/internal.h | 8 | ||||
-rw-r--r-- | audio/out/push.c | 15 |
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. |