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))