client API: avoid returning stale value on property notifications

This could happen if a property was flagged as changed, then updated,
then flagged again, but gen_property_change_event() was called before
the value was updated a second time. Then the function simply returned
the old value, and would later trigger a new change event again.

This was considered acceptable before, since property notifications are
asynchronous anyway (so they may always be "outdated", it just mattered
whether the most recent value was eventually delivered).

But consider ordering with events. It seems desirable that specific
important events (e.g. MPV_EVENT_START_FILE) should not be followed by
property updates that happened before it, because that would make
application logic really a mess, and property notification near-useless
in certain cases.

Avoid this by never returning a value if it was marked changed, but not
updated yet.

Unfortunately, this could lead to clients never receiving a value (or
receiving it with a high random delay), if they're too slow to read it
(or the property simply updates too often). Note that this is done for
_all_ property notifications, not just returned events. Hopefully not a
problem in practice. If it turns out to be one, this mechanism could be
restricted to actually returned events, for which this really matters.
This commit is contained in:
wm4 2020-03-06 23:59:21 +01:00
parent 575197ff8b
commit 8a4f812b76
1 changed files with 8 additions and 4 deletions

View File

@ -1638,10 +1638,12 @@ static void send_client_property_changes(struct mpv_handle *ctx)
changed = true; changed = true;
} }
if (changed) { // Avoid retriggering the change event if the property didn't change,
ctx->new_property_events = true; // and the previous value was actually returned to the client.
} else if (prop->value_ret_ts == prop->value_ts) { if (!changed && prop->value_ret_ts == prop->value_ts) {
prop->value_ret_ts = prop->change_ts; // no change => no event prop->value_ret_ts = prop->change_ts; // no change => no event
} else {
ctx->new_property_events = true;
} }
prop->value_ts = prop->change_ts; prop->value_ts = prop->change_ts;
@ -1698,7 +1700,9 @@ static bool gen_property_change_event(struct mpv_handle *ctx)
struct observe_property *prop = ctx->properties[ctx->cur_property_index++]; struct observe_property *prop = ctx->properties[ctx->cur_property_index++];
if (prop->value_ret_ts != prop->value_ts) { if (prop->value_ts == prop->change_ts && // not a stale value?
prop->value_ret_ts != prop->value_ts) // other value than last time?
{
prop->value_ret_ts = prop->value_ts; prop->value_ret_ts = prop->value_ts;
prop_unref(ctx->cur_property); prop_unref(ctx->cur_property);
ctx->cur_property = prop; ctx->cur_property = prop;