From 96186438ec488f65bfcdbd46af3cbc7bb4fdbe58 Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Wed, 14 Sep 2016 14:25:54 -0400 Subject: [PATCH] Remote pausing Support for remote pausing, and with it, support for Netplay pausing the frontend correctly. With this patch alone this doesn't work, since there's no clean way for the frontend to tell Netplay that it's paused. --- network/netplay/netplay.c | 52 ++++++++++++++++++++++++++----- network/netplay/netplay.h | 18 +++++++++-- network/netplay/netplay_net.c | 3 +- network/netplay/netplay_private.h | 4 +-- runloop.c | 8 ++++- 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 1d09b6b18d..51a67e74cc 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -299,11 +299,11 @@ static bool netplay_get_cmd(netplay_t *netplay) return netplay_cmd_nak(netplay); case NETPLAY_CMD_PAUSE: - command_event(CMD_EVENT_PAUSE, NULL); + netplay->remote_paused = true; return true; case NETPLAY_CMD_RESUME: - command_event(CMD_EVENT_UNPAUSE, NULL); + netplay->remote_paused = false; return true; default: break; @@ -360,7 +360,7 @@ static int poll_input(netplay_t *netplay, bool block) RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n", netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES); - if (netplay->timeout_cnt >= MAX_RETRIES) + if (netplay->timeout_cnt >= MAX_RETRIES && !netplay->remote_paused) return -1; } while (had_input || (block && (netplay->read_frame_count <= netplay->self_frame_count))); @@ -434,7 +434,12 @@ static bool netplay_poll(netplay_t *netplay) if (netplay->stall) { retro_time_t now = cpu_features_get_time_usec(); - if (now - netplay->stall_time >= MAX_STALL_TIME_USEC) + if (netplay->remote_paused) + { + /* Don't stall out while they're paused */ + netplay->stall_time = now; + } + else if (now - netplay->stall_time >= MAX_STALL_TIME_USEC) { /* Stalled out! */ netplay->has_connection = false; @@ -964,11 +969,20 @@ int16_t input_state_spectate_client(unsigned port, unsigned device, * * Pre-frame for Netplay. * Call this before running retro_run(). + * + * Returns: true (1) if the frontend is cleared to emulate the frame, false (0) + * if we're stalled or paused **/ -void netplay_pre_frame(netplay_t *netplay) +bool netplay_pre_frame(netplay_t *netplay) { retro_assert(netplay && netplay->net_cbs->pre_frame); + if (netplay->local_paused) + { + /* FIXME: This is an ugly way to learn we're not paused anymore */ + netplay_frontend_paused(netplay, false); + } netplay->net_cbs->pre_frame(netplay); + return (!netplay->stall && !netplay->remote_paused); } /** @@ -985,6 +999,25 @@ void netplay_post_frame(netplay_t *netplay) netplay->net_cbs->post_frame(netplay); } +/** + * netplay_frontend_paused + * @netplay : pointer to netplay object + * @paused : true if frontend is paused + * + * Inform Netplay of the frontend's pause state (paused or otherwise) + **/ +void netplay_frontend_paused(netplay_t *netplay, bool paused) +{ + /* Nothing to do if we already knew this */ + if (netplay->local_paused == paused) + return; + + fprintf(stderr, "Paused? %d\n", paused); + netplay->local_paused = paused; + if (netplay->has_connection) + netplay_send_raw_cmd(netplay, paused ? NETPLAY_CMD_PAUSE : NETPLAY_CMD_RESUME, NULL, 0); +} + void deinit_netplay(void) { netplay_t *netplay = (netplay_t*)netplay_data; @@ -1060,8 +1093,7 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) netplay_post_frame((netplay_t*)netplay_data); break; case RARCH_NETPLAY_CTL_PRE_FRAME: - netplay_pre_frame((netplay_t*)netplay_data); - break; + return netplay_pre_frame((netplay_t*)netplay_data); case RARCH_NETPLAY_CTL_FLIP_PLAYERS: { bool *state = (bool*)data; @@ -1076,6 +1108,12 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL); } break; + case RARCH_NETPLAY_CTL_PAUSE: + netplay_frontend_paused((netplay_t*)netplay_data, true); + break; + case RARCH_NETPLAY_CTL_UNPAUSE: + netplay_frontend_paused((netplay_t*)netplay_data, false); + break; default: case RARCH_NETPLAY_CTL_NONE: break; diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 3aac5bf1c0..54a32fb789 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -35,7 +35,9 @@ enum rarch_netplay_ctl_state RARCH_NETPLAY_CTL_FULLSCREEN_TOGGLE, RARCH_NETPLAY_CTL_POST_FRAME, RARCH_NETPLAY_CTL_PRE_FRAME, - RARCH_NETPLAY_CTL_IS_DATA_INITED + RARCH_NETPLAY_CTL_IS_DATA_INITED, + RARCH_NETPLAY_CTL_PAUSE, + RARCH_NETPLAY_CTL_UNPAUSE }; enum netplay_cmd @@ -154,8 +156,11 @@ void netplay_free(netplay_t *handle); * * Pre-frame for Netplay. * Call this before running retro_run(). + * + * Returns: true (1) if the frontend is clear to emulate the frame, false (0) + * if we're stalled or paused **/ -void netplay_pre_frame(netplay_t *handle); +bool netplay_pre_frame(netplay_t *handle); /** * netplay_post_frame: @@ -167,6 +172,15 @@ void netplay_pre_frame(netplay_t *handle); **/ void netplay_post_frame(netplay_t *handle); +/** + * netplay_frontend_paused + * @netplay : pointer to netplay object + * @paused : true if frontend is paused + * + * Inform Netplay of the frontend's pause state (paused or otherwise) + **/ +void netplay_frontend_paused(netplay_t *netplay, bool paused); + /** * init_netplay: * diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index ee9a13c5df..05c106f517 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -136,7 +136,8 @@ static void netplay_net_post_frame(netplay_t *netplay) netplay->is_replay = false; } - /* If we're supposed to stall, rewind */ + /* If we're supposed to stall, rewind (we shouldn't get this far if we're + * stalled, so this is a last resort) */ if (netplay->stall) { retro_ctx_serialize_info_t serial_info; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index e8bf820e40..56cd84c29a 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -139,8 +139,8 @@ struct netplay /* Netplay pausing */ - bool pause; - uint32_t pause_frame; + bool local_paused; + bool remote_paused; /* And stalling */ uint32_t stall_frames; diff --git a/runloop.c b/runloop.c index 9a39afad95..86d5082042 100644 --- a/runloop.c +++ b/runloop.c @@ -1576,7 +1576,13 @@ int runloop_iterate(unsigned *sleep_ms) #endif #ifdef HAVE_NETPLAY - netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL); + if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL)) + { + /* Paused due to Netplay */ + core_poll(); + *sleep_ms = 10; + return 1; + } #endif if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))