mirror of https://github.com/mpv-player/mpv
client API: report pause/unpause reason
Not sure about this... might redo. At least this provides a case of a broadcasted event, which requires per-event data allocation. See github issue #576.
This commit is contained in:
parent
5d7007c644
commit
0adb8a9aaf
|
@ -365,6 +365,25 @@ List of events
|
|||
``pause``
|
||||
Playback was paused.
|
||||
|
||||
Has the following event fields:
|
||||
|
||||
``real_paused``
|
||||
Current playback pause state as boolean.
|
||||
|
||||
``user_paused``
|
||||
User requested pause state.
|
||||
|
||||
``by_command``
|
||||
If the action was triggered by an input command (or via an user key
|
||||
binding). It's false if it was an automatic action.
|
||||
|
||||
``by_cache``
|
||||
If the action was triggered by a low (or recovering) cache state.
|
||||
|
||||
``by_keep_open``
|
||||
If the pausing was triggered because the end of playback was reached,
|
||||
and the "keep-open" option is enabled, 0 otherwise.
|
||||
|
||||
``unpause``
|
||||
Playback was unpaused.
|
||||
|
||||
|
|
|
@ -889,6 +889,32 @@ typedef struct mpv_event_log_message {
|
|||
const char *text;
|
||||
} mpv_event_log_message;
|
||||
|
||||
typedef struct mpv_event_pause_reason {
|
||||
/**
|
||||
* Actual pause state (0 or 1)
|
||||
*/
|
||||
int real_paused;
|
||||
/**
|
||||
* User requested pause state (0 or 1)
|
||||
*/
|
||||
int user_paused;
|
||||
/**
|
||||
* 1 if the action was triggered by an input command (or via an user key
|
||||
* binding), 0 otherwise.
|
||||
*/
|
||||
int by_command;
|
||||
/**
|
||||
* 1 if the action was triggered by a low (or recovering) cache state,
|
||||
* 0 otherwise.
|
||||
*/
|
||||
int by_cache;
|
||||
/**
|
||||
* 1 if the pausing was triggered because the end of playback was reached,
|
||||
* and the "keep-open" option is enabled, 0 otherwise.
|
||||
*/
|
||||
int by_keep_open;
|
||||
} mpv_event_pause_reason;
|
||||
|
||||
typedef struct mpv_event_script_input_dispatch {
|
||||
/**
|
||||
* Arbitrary integer value that was provided as argument to the
|
||||
|
@ -938,6 +964,8 @@ typedef struct mpv_event {
|
|||
* The meaning and contents of data member depend on the event_id:
|
||||
* MPV_EVENT_GET_PROPERTY_REPLY: mpv_event_property*
|
||||
* MPV_EVENT_LOG_MESSAGE: mpv_event_log_message*
|
||||
* MPV_EVENT_PAUSE: mpv_event_pause_reason*
|
||||
* MPV_EVENT_UNPAUSE: mpv_event_pause_reason*
|
||||
* MPV_EVENT_SCRIPT_INPUT_DISPATCH: mpv_event_script_input_dispatch*
|
||||
* MPV_EVENT_CLIENT_MESSAGE: mpv_event_client_message*
|
||||
* other: NULL
|
||||
|
|
|
@ -324,23 +324,37 @@ static void status_reply(struct mpv_handle *ctx, int event,
|
|||
send_reply(ctx, userdata, &reply);
|
||||
}
|
||||
|
||||
// set ev->data to a new copy of the original data
|
||||
static void dup_event_data(struct mpv_event *ev)
|
||||
{
|
||||
switch (ev->event_id) {
|
||||
case MPV_EVENT_PAUSE:
|
||||
case MPV_EVENT_UNPAUSE:
|
||||
ev->data = talloc_memdup(NULL, ev->data, sizeof(mpv_event_pause_reason));
|
||||
break;
|
||||
default:
|
||||
// Doesn't use events with memory allocation.
|
||||
if (ev->data)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data)
|
||||
{
|
||||
struct mp_client_api *clients = mpctx->clients;
|
||||
|
||||
struct mpv_event event_data = {
|
||||
.event_id = event,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&clients->lock);
|
||||
|
||||
for (int n = 0; n < clients->num_clients; n++)
|
||||
for (int n = 0; n < clients->num_clients; n++) {
|
||||
struct mpv_event event_data = {
|
||||
.event_id = event,
|
||||
.data = data,
|
||||
};
|
||||
dup_event_data(&event_data);
|
||||
send_event(clients->clients[n], &event_data);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&clients->lock);
|
||||
|
||||
talloc_free(data);
|
||||
}
|
||||
|
||||
int mp_client_send_event(struct MPContext *mpctx, const char *client_name,
|
||||
|
|
|
@ -877,9 +877,9 @@ static int mp_property_pause(m_option_t *prop, int action, void *arg,
|
|||
|
||||
if (action == M_PROPERTY_SET) {
|
||||
if (*(int *)arg) {
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
} else {
|
||||
unpause_player(mpctx);
|
||||
unpause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
}
|
||||
return M_PROPERTY_OK;
|
||||
}
|
||||
|
@ -3369,12 +3369,12 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
|||
}
|
||||
|
||||
if (cmd->flags & MP_PAUSING)
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
if (cmd->flags & MP_PAUSING_TOGGLE) {
|
||||
if (opts->pause)
|
||||
unpause_player(mpctx);
|
||||
unpause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
else
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,11 @@ enum seek_type {
|
|||
MPSEEK_FACTOR,
|
||||
};
|
||||
|
||||
// A bit-mask would be best, but I preferred not to use that with the client API.
|
||||
#define PAUSE_BY_COMMAND ((mpv_event_pause_reason){.by_command=1})
|
||||
#define PAUSE_BY_CACHE ((mpv_event_pause_reason){.by_cache=1})
|
||||
#define PAUSE_BY_KEEP_OPEN ((mpv_event_pause_reason){.by_keep_open=1})
|
||||
|
||||
struct track {
|
||||
enum stream_type type;
|
||||
|
||||
|
@ -420,8 +425,8 @@ void set_osd_function(struct MPContext *mpctx, int osd_function);
|
|||
void set_osd_subtitle(struct MPContext *mpctx, const char *text);
|
||||
|
||||
// playloop.c
|
||||
void pause_player(struct MPContext *mpctx);
|
||||
void unpause_player(struct MPContext *mpctx);
|
||||
void pause_player(struct MPContext *mpctx, mpv_event_pause_reason reason);
|
||||
void unpause_player(struct MPContext *mpctx, mpv_event_pause_reason reason);
|
||||
void add_step_frame(struct MPContext *mpctx, int dir);
|
||||
void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
|
||||
int exact, bool immediate);
|
||||
|
|
|
@ -1339,7 +1339,7 @@ goto_reopen_demuxer: ;
|
|||
get_relative_time(mpctx); // reset current delta
|
||||
|
||||
if (mpctx->opts->pause)
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
|
||||
mp_notify(mpctx, MPV_EVENT_PLAYBACK_START, NULL);
|
||||
|
||||
|
|
16
player/lua.c
16
player/lua.c
|
@ -442,6 +442,22 @@ static int script_wait_event(lua_State *L)
|
|||
lua_setfield(L, -2, "args"); // event
|
||||
break;
|
||||
}
|
||||
case MPV_EVENT_PAUSE:
|
||||
case MPV_EVENT_UNPAUSE:
|
||||
{
|
||||
mpv_event_pause_reason *msg = event->data;
|
||||
lua_pushboolean(L, msg->real_paused);
|
||||
lua_setfield(L, -2, "real_paused");
|
||||
lua_pushboolean(L, msg->user_paused);
|
||||
lua_setfield(L, -2, "user_paused");
|
||||
lua_pushboolean(L, msg->by_command);
|
||||
lua_setfield(L, -2, "by_command");
|
||||
lua_pushboolean(L, msg->by_cache);
|
||||
lua_setfield(L, -2, "by_cache");
|
||||
lua_pushboolean(L, msg->by_keep_open);
|
||||
lua_setfield(L, -2, "by_keep_open");
|
||||
break;
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,17 +78,15 @@ static const char av_desync_help_text[] =
|
|||
"If none of this helps you, file a bug report.\n\n";
|
||||
|
||||
|
||||
void pause_player(struct MPContext *mpctx)
|
||||
void pause_player(struct MPContext *mpctx, mpv_event_pause_reason reason)
|
||||
{
|
||||
mp_notify(mpctx, MPV_EVENT_PAUSE, NULL);
|
||||
|
||||
mpctx->opts->pause = 1;
|
||||
|
||||
if (mpctx->video_out)
|
||||
vo_control(mpctx->video_out, VOCTRL_RESTORE_SCREENSAVER, NULL);
|
||||
|
||||
if (mpctx->paused)
|
||||
return;
|
||||
goto end;
|
||||
mpctx->paused = true;
|
||||
mpctx->step_frames = 0;
|
||||
mpctx->time_frame -= get_relative_time(mpctx);
|
||||
|
@ -107,22 +105,25 @@ void pause_player(struct MPContext *mpctx)
|
|||
|
||||
if (!mpctx->opts->quiet)
|
||||
MP_SMODE(mpctx, "ID_PAUSED\n");
|
||||
|
||||
end:
|
||||
reason.user_paused = !!mpctx->opts->pause;
|
||||
reason.real_paused = !!mpctx->paused;
|
||||
mp_notify(mpctx, MPV_EVENT_UNPAUSE, &reason);
|
||||
}
|
||||
|
||||
void unpause_player(struct MPContext *mpctx)
|
||||
void unpause_player(struct MPContext *mpctx, mpv_event_pause_reason reason)
|
||||
{
|
||||
mp_notify(mpctx, MPV_EVENT_UNPAUSE, NULL);
|
||||
|
||||
mpctx->opts->pause = 0;
|
||||
|
||||
if (mpctx->video_out && mpctx->opts->stop_screensaver)
|
||||
vo_control(mpctx->video_out, VOCTRL_KILL_SCREENSAVER, NULL);
|
||||
|
||||
if (!mpctx->paused)
|
||||
return;
|
||||
goto end;
|
||||
// Don't actually unpause while cache is loading.
|
||||
if (mpctx->paused_for_cache)
|
||||
return;
|
||||
goto end;
|
||||
mpctx->paused = false;
|
||||
mpctx->osd_function = 0;
|
||||
|
||||
|
@ -131,6 +132,11 @@ void unpause_player(struct MPContext *mpctx)
|
|||
if (mpctx->video_out && mpctx->d_video && mpctx->video_out->config_ok)
|
||||
vo_control(mpctx->video_out, VOCTRL_RESUME, NULL); // resume video
|
||||
(void)get_relative_time(mpctx); // ignore time that passed during pause
|
||||
|
||||
end:
|
||||
reason.user_paused = !!mpctx->opts->pause;
|
||||
reason.real_paused = !!mpctx->paused;
|
||||
mp_notify(mpctx, MPV_EVENT_UNPAUSE, &reason);
|
||||
}
|
||||
|
||||
static void draw_osd(struct MPContext *mpctx)
|
||||
|
@ -159,12 +165,12 @@ void add_step_frame(struct MPContext *mpctx, int dir)
|
|||
return;
|
||||
if (dir > 0) {
|
||||
mpctx->step_frames += 1;
|
||||
unpause_player(mpctx);
|
||||
unpause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
} else if (dir < 0) {
|
||||
if (!mpctx->backstep_active && !mpctx->hrseek_active) {
|
||||
mpctx->backstep_active = true;
|
||||
mpctx->backstep_start_seek_ts = mpctx->vo_pts_history_seek_ts;
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,14 +690,14 @@ static void handle_pause_on_low_cache(struct MPContext *mpctx)
|
|||
if (cache < 0 || cache >= opts->stream_cache_min_percent || idle) {
|
||||
mpctx->paused_for_cache = false;
|
||||
if (!opts->pause)
|
||||
unpause_player(mpctx);
|
||||
unpause_player(mpctx, PAUSE_BY_CACHE);
|
||||
}
|
||||
} else {
|
||||
if (cache >= 0 && cache <= opts->stream_cache_pause && !idle &&
|
||||
opts->stream_cache_pause < opts->stream_cache_min_percent)
|
||||
{
|
||||
bool prev_paused_user = opts->pause;
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_CACHE);
|
||||
mpctx->paused_for_cache = true;
|
||||
opts->pause = prev_paused_user;
|
||||
}
|
||||
|
@ -857,7 +863,7 @@ static void handle_keep_open(struct MPContext *mpctx)
|
|||
if (opts->keep_open && mpctx->stop_play == AT_END_OF_FILE) {
|
||||
mpctx->stop_play = KEEP_PLAYING;
|
||||
mpctx->playback_pts = mpctx->last_vo_pts;
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_KEEP_OPEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1261,7 +1267,7 @@ void run_playloop(struct MPContext *mpctx)
|
|||
if (new_frame_shown)
|
||||
mpctx->step_frames--;
|
||||
if (mpctx->step_frames == 0)
|
||||
pause_player(mpctx);
|
||||
pause_player(mpctx, PAUSE_BY_COMMAND);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue