diff --git a/audio/out/ao.c b/audio/out/ao.c index e7af02276f..817aa29399 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -402,6 +402,7 @@ void ao_reset(struct ao *ao) { if (ao->api->reset) ao->api->reset(ao); + atomic_fetch_and(&ao->events_, ~(unsigned int)AO_EVENT_UNDERRUN); } // Pause playback. Keep the current buffer. ao_get_delay() must return the @@ -457,6 +458,14 @@ void ao_hotplug_event(struct ao *ao) ao_add_events(ao, AO_EVENT_HOTPLUG); } +void ao_underrun_event(struct ao *ao) +{ + // Racy check, but it's just for the message. + if (!(atomic_load(&ao->events_) & AO_EVENT_UNDERRUN)) + MP_WARN(ao, "Device underrun detected.\n"); + ao_add_events(ao, AO_EVENT_UNDERRUN); +} + bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s, struct mp_chmap *map) { @@ -517,6 +526,11 @@ const char *ao_get_description(struct ao *ao) return ao->driver->description; } +bool ao_get_reports_underruns(struct ao *ao) +{ + return ao->driver->reports_underruns; +} + bool ao_untimed(struct ao *ao) { return ao->untimed; diff --git a/audio/out/ao.h b/audio/out/ao.h index d66391ef1d..f8b3e676fa 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -49,6 +49,7 @@ enum { AO_EVENT_RELOAD = 1, AO_EVENT_HOTPLUG = 2, AO_EVENT_INITIAL_UNBLOCK = 4, + AO_EVENT_UNDERRUN = 8, }; enum { @@ -100,6 +101,7 @@ void ao_get_format(struct ao *ao, int *samplerate, int *format, struct mp_chmap *channels); const char *ao_get_name(struct ao *ao); const char *ao_get_description(struct ao *ao); +bool ao_get_reports_underruns(struct ao *ao); bool ao_untimed(struct ao *ao); int ao_play(struct ao *ao, void **data, int samples, int flags); int ao_control(struct ao *ao, enum aocontrol cmd, void *arg); diff --git a/audio/out/internal.h b/audio/out/internal.h index bf769d7e1c..807f124a17 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -68,7 +68,7 @@ struct ao { char *redirect; // Internal events (use ao_request_reload(), ao_hotplug_event()) - atomic_int events_; + atomic_uint events_; // Float gain multiplicator mp_atomic_float gain; @@ -134,6 +134,11 @@ struct ao_driver { // first play() call is done. Encode mode uses this, and push mode // respects it automatically (don't use with pull mode). bool initially_blocked; + // Whether underruns are strictly _always_ reported via ao_underrun_event(). + // Do not set this to true if underruns may be missed in some way. If the + // AO can't guarantee to play silence after underruns, it may be better not + // to set this. + bool reports_underruns; // Init the device using ao->format/ao->channels/ao->samplerate. If the // device doesn't accept these parameters, you can attempt to negotiate // fallback parameters, and set the ao format fields accordingly. @@ -206,6 +211,7 @@ struct pollfd; int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, pthread_mutex_t *lock); void ao_wakeup_poll(struct ao *ao); +void ao_underrun_event(struct ao *ao); bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s, struct mp_chmap *map); diff --git a/player/audio.c b/player/audio.c index e93f6b49a9..20f80256b2 100644 --- a/player/audio.c +++ b/player/audio.c @@ -855,6 +855,8 @@ void fill_audio_out_buffers(struct MPContext *mpctx) int playsize = ao_get_space(mpctx->ao); + ao_query_and_reset_events(mpctx->ao, AO_EVENT_UNDERRUN); + int skip = 0; bool sync_known = get_sync_samples(mpctx, &skip); if (skip > 0) {