summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/client-api-changes.rst1
-rw-r--r--libmpv/client.h21
-rw-r--r--player/client.c32
-rw-r--r--player/command.h2
4 files changed, 40 insertions, 16 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index 10bcb942ba..8fa325a870 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -25,6 +25,7 @@ API changes
::
+ 1.13 - add MPV_EVENT_QUEUE_OVERFLOW
1.12 - add class Handle to qthelper.hpp
- improve opengl_cb.h API uninitialization behavior, and fix the qml
example
diff --git a/libmpv/client.h b/libmpv/client.h
index a86717df08..7208912ee0 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -167,7 +167,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
-#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 12)
+#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 13)
/**
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
@@ -1117,7 +1117,17 @@ typedef enum mpv_event_id {
* "chapter" property. The event is redundant, and might
* be removed in the far future.
*/
- MPV_EVENT_CHAPTER_CHANGE = 23
+ MPV_EVENT_CHAPTER_CHANGE = 23,
+ /**
+ * Happens if the internal per-mpv_handle ringbuffer overflows, and at
+ * least 1 event had to be dropped. This can happen if the client doesn't
+ * read the event queue quickly enough with mpv_wait_event(), or if the
+ * client makes a very large number of asynchronous calls at once.
+ *
+ * Event delivery will continue normally once this event was returned
+ * (this forces the client to empty the queue completely).
+ */
+ MPV_EVENT_QUEUE_OVERFLOW = 24
// Internal note: adjust INTERNAL_EVENT_BASE when adding new events.
} mpv_event_id;
@@ -1353,8 +1363,8 @@ int mpv_request_log_messages(mpv_handle *ctx, const char *min_level);
* The API won't complain if more than one thread calls this, but it will cause
* race conditions in the client when accessing the shared mpv_event struct.
* Note that most other API functions are not restricted by this, and no API
- * function internally calls mpv_wait_event(). This does not apply to concurrent
- * calls of this function on different mpv_handles: these are always safe.
+ * function internally calls mpv_wait_event(). Additionally, concurrent calls
+ * to different mpv_handles are always safe.
*
* @param timeout Timeout in seconds, after which the function returns even if
* no event was received. A MPV_EVENT_NONE is returned on
@@ -1364,7 +1374,8 @@ int mpv_request_log_messages(mpv_handle *ctx, const char *min_level);
* fields in the struct) stay valid until the next mpv_wait_event()
* call, or until the mpv_handle is destroyed. You must not write to
* the struct, and all memory referenced by it will be automatically
- * released by the API. The return value is never NULL.
+ * released by the API on the next mpv_wait_event() call, or when the
+ * context is destroyed. The return value is never NULL.
*/
mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout);
diff --git a/player/client.c b/player/client.c
index 50daf45393..c4f02b84c8 100644
--- a/player/client.c
+++ b/player/client.c
@@ -107,7 +107,6 @@ struct mpv_handle {
uint64_t event_mask;
bool queued_wakeup;
- bool choke_warning;
int suspend_count;
mpv_event *events; // ringbuffer of max_events entries
@@ -115,6 +114,7 @@ struct mpv_handle {
int first_event; // events[first_event] is the first readable event
int num_events; // number of readable events
int reserved_events; // number of entries reserved for replies
+ bool choked; // recovering from queue overflow
struct observe_property **properties;
int num_properties;
@@ -541,7 +541,8 @@ static int reserve_reply(struct mpv_handle *ctx)
{
int res = MPV_ERROR_EVENT_QUEUE_FULL;
pthread_mutex_lock(&ctx->lock);
- if (ctx->reserved_events + ctx->num_events < ctx->max_events) {
+ if (ctx->reserved_events + ctx->num_events < ctx->max_events && !ctx->choked)
+ {
ctx->reserved_events++;
res = 0;
}
@@ -567,14 +568,17 @@ static int send_event(struct mpv_handle *ctx, struct mpv_event *event, bool copy
uint64_t mask = 1ULL << event->event_id;
if (ctx->property_event_masks & mask)
notify_property_events(ctx, mask);
+ int r;
if (!(ctx->event_mask & mask)) {
- pthread_mutex_unlock(&ctx->lock);
- return 0;
- }
- int r = append_event(ctx, *event, copy);
- if (r < 0 && !ctx->choke_warning) {
- mp_err(ctx->log, "Too many events queued.\n");
- ctx->choke_warning = true;
+ r = 0;
+ } else if (ctx->choked) {
+ r = -1;
+ } else {
+ r = append_event(ctx, *event, copy);
+ if (r < 0) {
+ MP_ERR(ctx, "Too many events queued.\n");
+ ctx->choked = true;
+ }
}
pthread_mutex_unlock(&ctx->lock);
return r;
@@ -729,6 +733,12 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout)
while (1) {
if (ctx->queued_wakeup)
deadline = 0;
+ // Recover from overflow.
+ if (ctx->choked && !ctx->num_events) {
+ ctx->choked = false;
+ event->event_id = MPV_EVENT_QUEUE_OVERFLOW;
+ break;
+ }
// This will almost surely lead to a deadlock. (Polling is still ok.)
if (ctx->suspend_count && timeout > 0) {
MP_ERR(ctx, "attempting to wait while core is suspended");
@@ -741,10 +751,11 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout)
talloc_steal(event, event->data);
break;
}
+ // If there's a changed property, generate change event (never queued).
if (gen_property_change_event(ctx))
break;
+ // Pop item from message queue, and return as event.
if (ctx->messages) {
- // Poll the log message queue. Currently we can't/don't do better.
struct mp_log_buffer_entry *msg =
mp_msg_log_buffer_read(ctx->messages);
if (msg) {
@@ -1608,6 +1619,7 @@ static const char *const event_table[] = {
[MPV_EVENT_PLAYBACK_RESTART] = "playback-restart",
[MPV_EVENT_PROPERTY_CHANGE] = "property-change",
[MPV_EVENT_CHAPTER_CHANGE] = "chapter-change",
+ [MPV_EVENT_QUEUE_OVERFLOW] = "event-queue-overflow",
};
const char *mpv_event_name(mpv_event_id event)
diff --git a/player/command.h b/player/command.h
index d4097fee6f..d6891b66cd 100644
--- a/player/command.h
+++ b/player/command.h
@@ -42,7 +42,7 @@ uint64_t mp_get_property_event_mask(const char *name);
enum {
// Must start with the first unused positive value in enum mpv_event_id
// MPV_EVENT_* and MP_EVENT_* must not overlap.
- INTERNAL_EVENT_BASE = 24,
+ INTERNAL_EVENT_BASE = 25,
MP_EVENT_CACHE_UPDATE,
MP_EVENT_WIN_RESIZE,
MP_EVENT_WIN_STATE,