From 14348f42b2cbe855b77c7fac4dbeb136b8a2f8f1 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 11 May 2024 16:40:22 +0200 Subject: [PATCH] Terminate on controller error This is particularly important to react to server socket disconnection since video and audio may be disabled. PR #4868 --- app/src/controller.c | 32 +++++++++++++++++++++++++++++--- app/src/controller.h | 11 ++++++++++- app/src/events.h | 1 + app/src/receiver.c | 9 ++++++++- app/src/receiver.h | 10 +++++++++- app/src/scrcpy.c | 20 +++++++++++++++++++- 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/app/src/controller.c b/app/src/controller.c index 499cfd3c..edd767eb 100644 --- a/app/src/controller.c +++ b/app/src/controller.c @@ -6,8 +6,19 @@ #define SC_CONTROL_MSG_QUEUE_MAX 64 +static void +sc_controller_receiver_on_error(struct sc_receiver *receiver, void *userdata) { + (void) receiver; + + struct sc_controller *controller = userdata; + // Forward the event to the controller listener + controller->cbs->on_error(controller, controller->cbs_userdata); +} + bool -sc_controller_init(struct sc_controller *controller, sc_socket control_socket) { +sc_controller_init(struct sc_controller *controller, sc_socket control_socket, + const struct sc_controller_callbacks *cbs, + void *cbs_userdata) { sc_vecdeque_init(&controller->queue); bool ok = sc_vecdeque_reserve(&controller->queue, SC_CONTROL_MSG_QUEUE_MAX); @@ -15,7 +26,12 @@ sc_controller_init(struct sc_controller *controller, sc_socket control_socket) { return false; } - ok = sc_receiver_init(&controller->receiver, control_socket); + static const struct sc_receiver_callbacks receiver_cbs = { + .on_error = sc_controller_receiver_on_error, + }; + + ok = sc_receiver_init(&controller->receiver, control_socket, &receiver_cbs, + controller); if (!ok) { sc_vecdeque_destroy(&controller->queue); return false; @@ -39,6 +55,10 @@ sc_controller_init(struct sc_controller *controller, sc_socket control_socket) { controller->control_socket = control_socket; controller->stopped = false; + assert(cbs && cbs->on_error); + controller->cbs = cbs; + controller->cbs_userdata = cbs_userdata; + return true; } @@ -125,10 +145,16 @@ run_controller(void *data) { sc_control_msg_destroy(&msg); if (!ok) { LOGD("Could not write msg to socket"); - break; + goto error; } } + return 0; + +error: + controller->cbs->on_error(controller, controller->cbs_userdata); + + return 1; // ignored } bool diff --git a/app/src/controller.h b/app/src/controller.h index 1e44427e..353d4d0d 100644 --- a/app/src/controller.h +++ b/app/src/controller.h @@ -22,10 +22,19 @@ struct sc_controller { bool stopped; struct sc_control_msg_queue queue; struct sc_receiver receiver; + + const struct sc_controller_callbacks *cbs; + void *cbs_userdata; +}; + +struct sc_controller_callbacks { + void (*on_error)(struct sc_controller *controller, void *userdata); }; bool -sc_controller_init(struct sc_controller *controller, sc_socket control_socket); +sc_controller_init(struct sc_controller *controller, sc_socket control_socket, + const struct sc_controller_callbacks *cbs, + void *cbs_userdata); void sc_controller_configure(struct sc_controller *controller, diff --git a/app/src/events.h b/app/src/events.h index 8bfa2582..3cf2b1dd 100644 --- a/app/src/events.h +++ b/app/src/events.h @@ -7,3 +7,4 @@ #define SC_EVENT_RECORDER_ERROR (SDL_USEREVENT + 6) #define SC_EVENT_SCREEN_INIT_SIZE (SDL_USEREVENT + 7) #define SC_EVENT_TIME_LIMIT_REACHED (SDL_USEREVENT + 8) +#define SC_EVENT_CONTROLLER_ERROR (SDL_USEREVENT + 9) diff --git a/app/src/receiver.c b/app/src/receiver.c index f4ebd3f8..fb923ac4 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -10,7 +10,8 @@ #include "util/str.h" bool -sc_receiver_init(struct sc_receiver *receiver, sc_socket control_socket) { +sc_receiver_init(struct sc_receiver *receiver, sc_socket control_socket, + const struct sc_receiver_callbacks *cbs, void *cbs_userdata) { bool ok = sc_mutex_init(&receiver->mutex); if (!ok) { return false; @@ -20,6 +21,10 @@ sc_receiver_init(struct sc_receiver *receiver, sc_socket control_socket) { receiver->acksync = NULL; receiver->uhid_devices = NULL; + assert(cbs && cbs->on_error); + receiver->cbs = cbs; + receiver->cbs_userdata = cbs_userdata; + return true; } @@ -152,6 +157,8 @@ run_receiver(void *data) { } } + receiver->cbs->on_error(receiver, receiver->cbs_userdata); + return 0; } diff --git a/app/src/receiver.h b/app/src/receiver.h index ba84c0ab..ef83978f 100644 --- a/app/src/receiver.h +++ b/app/src/receiver.h @@ -19,10 +19,18 @@ struct sc_receiver { struct sc_acksync *acksync; struct sc_uhid_devices *uhid_devices; + + const struct sc_receiver_callbacks *cbs; + void *cbs_userdata; +}; + +struct sc_receiver_callbacks { + void (*on_error)(struct sc_receiver *receiver, void *userdata); }; bool -sc_receiver_init(struct sc_receiver *receiver, sc_socket control_socket); +sc_receiver_init(struct sc_receiver *receiver, sc_socket control_socket, + const struct sc_receiver_callbacks *cbs, void *cbs_userdata); void sc_receiver_destroy(struct sc_receiver *receiver); diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 5e7b19fd..b07611f1 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -174,6 +174,9 @@ event_loop(struct scrcpy *s) { case SC_EVENT_DEMUXER_ERROR: LOGE("Demuxer error"); return SCRCPY_EXIT_FAILURE; + case SC_EVENT_CONTROLLER_ERROR: + LOGE("Controller error"); + return SCRCPY_EXIT_FAILURE; case SC_EVENT_RECORDER_ERROR: LOGE("Recorder error"); return SCRCPY_EXIT_FAILURE; @@ -265,6 +268,16 @@ sc_audio_demuxer_on_ended(struct sc_demuxer *demuxer, } } +static void +sc_controller_on_error(struct sc_controller *controller, void *userdata) { + // Note: this function may be called twice, once from the controller thread + // and once from the receiver thread + (void) controller; + (void) userdata; + + PUSH_EVENT(SC_EVENT_CONTROLLER_ERROR); +} + static void sc_server_on_connection_failed(struct sc_server *server, void *userdata) { (void) server; @@ -553,7 +566,12 @@ scrcpy(struct scrcpy_options *options) { struct sc_mouse_processor *mp = NULL; if (options->control) { - if (!sc_controller_init(&s->controller, s->server.control_socket)) { + static const struct sc_controller_callbacks controller_cbs = { + .on_error = sc_controller_on_error, + }; + + if (!sc_controller_init(&s->controller, s->server.control_socket, + &controller_cbs, NULL)) { goto end; } controller_initialized = true;