diff --git a/app/meson.build b/app/meson.build index 319dd0b6..88b8ef8c 100644 --- a/app/meson.build +++ b/app/meson.build @@ -11,7 +11,7 @@ src = [ 'src/decoder.c', 'src/device_msg.c', 'src/icon.c', - 'src/file_handler.c', + 'src/file_pusher.c', 'src/fps_counter.c', 'src/frame_buffer.c', 'src/input_manager.c', diff --git a/app/src/file_handler.c b/app/src/file_handler.c deleted file mode 100644 index 95d230ae..00000000 --- a/app/src/file_handler.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "file_handler.h" - -#include -#include - -#include "adb.h" -#include "util/log.h" -#include "util/process_intr.h" - -#define DEFAULT_PUSH_TARGET "/sdcard/Download/" - -static void -file_handler_request_destroy(struct file_handler_request *req) { - free(req->file); -} - -bool -file_handler_init(struct file_handler *file_handler, const char *serial, - const char *push_target) { - assert(serial); - - cbuf_init(&file_handler->queue); - - bool ok = sc_mutex_init(&file_handler->mutex); - if (!ok) { - return false; - } - - ok = sc_cond_init(&file_handler->event_cond); - if (!ok) { - sc_mutex_destroy(&file_handler->mutex); - return false; - } - - ok = sc_intr_init(&file_handler->intr); - if (!ok) { - sc_cond_destroy(&file_handler->event_cond); - sc_mutex_destroy(&file_handler->mutex); - return false; - } - - file_handler->serial = strdup(serial); - if (!file_handler->serial) { - LOG_OOM(); - sc_intr_destroy(&file_handler->intr); - sc_cond_destroy(&file_handler->event_cond); - sc_mutex_destroy(&file_handler->mutex); - return false; - } - - // lazy initialization - file_handler->initialized = false; - - file_handler->stopped = false; - - file_handler->push_target = push_target ? push_target : DEFAULT_PUSH_TARGET; - - return true; -} - -void -file_handler_destroy(struct file_handler *file_handler) { - sc_cond_destroy(&file_handler->event_cond); - sc_mutex_destroy(&file_handler->mutex); - sc_intr_destroy(&file_handler->intr); - free(file_handler->serial); - - struct file_handler_request req; - while (cbuf_take(&file_handler->queue, &req)) { - file_handler_request_destroy(&req); - } -} - -bool -file_handler_request(struct file_handler *file_handler, - file_handler_action_t action, char *file) { - // start file_handler if it's used for the first time - if (!file_handler->initialized) { - if (!file_handler_start(file_handler)) { - return false; - } - file_handler->initialized = true; - } - - LOGI("Request to %s %s", action == ACTION_INSTALL_APK ? "install" : "push", - file); - struct file_handler_request req = { - .action = action, - .file = file, - }; - - sc_mutex_lock(&file_handler->mutex); - bool was_empty = cbuf_is_empty(&file_handler->queue); - bool res = cbuf_push(&file_handler->queue, req); - if (was_empty) { - sc_cond_signal(&file_handler->event_cond); - } - sc_mutex_unlock(&file_handler->mutex); - return res; -} - -static int -run_file_handler(void *data) { - struct file_handler *file_handler = data; - struct sc_intr *intr = &file_handler->intr; - - const char *serial = file_handler->serial; - assert(serial); - - const char *push_target = file_handler->push_target; - assert(push_target); - - for (;;) { - sc_mutex_lock(&file_handler->mutex); - while (!file_handler->stopped && cbuf_is_empty(&file_handler->queue)) { - sc_cond_wait(&file_handler->event_cond, &file_handler->mutex); - } - if (file_handler->stopped) { - // stop immediately, do not process further events - sc_mutex_unlock(&file_handler->mutex); - break; - } - struct file_handler_request req; - bool non_empty = cbuf_take(&file_handler->queue, &req); - assert(non_empty); - (void) non_empty; - sc_mutex_unlock(&file_handler->mutex); - - if (req.action == ACTION_INSTALL_APK) { - LOGI("Installing %s...", req.file); - bool ok = adb_install(intr, serial, req.file, 0); - if (ok) { - LOGI("%s successfully installed", req.file); - } else { - LOGE("Failed to install %s", req.file); - } - } else { - LOGI("Pushing %s...", req.file); - bool ok = adb_push(intr, serial, req.file, push_target, 0); - if (ok) { - LOGI("%s successfully pushed to %s", req.file, push_target); - } else { - LOGE("Failed to push %s to %s", req.file, push_target); - } - } - - file_handler_request_destroy(&req); - } - return 0; -} - -bool -file_handler_start(struct file_handler *file_handler) { - LOGD("Starting file_handler thread"); - - bool ok = sc_thread_create(&file_handler->thread, run_file_handler, - "scrcpy-file", file_handler); - if (!ok) { - LOGC("Could not start file_handler thread"); - return false; - } - - return true; -} - -void -file_handler_stop(struct file_handler *file_handler) { - sc_mutex_lock(&file_handler->mutex); - file_handler->stopped = true; - sc_cond_signal(&file_handler->event_cond); - sc_intr_interrupt(&file_handler->intr); - sc_mutex_unlock(&file_handler->mutex); -} - -void -file_handler_join(struct file_handler *file_handler) { - sc_thread_join(&file_handler->thread, NULL); -} diff --git a/app/src/file_handler.h b/app/src/file_handler.h deleted file mode 100644 index 4c0313cc..00000000 --- a/app/src/file_handler.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef FILE_HANDLER_H -#define FILE_HANDLER_H - -#include "common.h" - -#include - -#include "adb.h" -#include "util/cbuf.h" -#include "util/thread.h" -#include "util/intr.h" - -typedef enum { - ACTION_INSTALL_APK, - ACTION_PUSH_FILE, -} file_handler_action_t; - -struct file_handler_request { - file_handler_action_t action; - char *file; -}; - -struct file_handler_request_queue CBUF(struct file_handler_request, 16); - -struct file_handler { - char *serial; - const char *push_target; - sc_thread thread; - sc_mutex mutex; - sc_cond event_cond; - bool stopped; - bool initialized; - struct file_handler_request_queue queue; - - struct sc_intr intr; -}; - -bool -file_handler_init(struct file_handler *file_handler, const char *serial, - const char *push_target); - -void -file_handler_destroy(struct file_handler *file_handler); - -bool -file_handler_start(struct file_handler *file_handler); - -void -file_handler_stop(struct file_handler *file_handler); - -void -file_handler_join(struct file_handler *file_handler); - -// take ownership of file, and will free() it -bool -file_handler_request(struct file_handler *file_handler, - file_handler_action_t action, - char *file); - -#endif diff --git a/app/src/file_pusher.c b/app/src/file_pusher.c new file mode 100644 index 00000000..738e3616 --- /dev/null +++ b/app/src/file_pusher.c @@ -0,0 +1,178 @@ +#include "file_pusher.h" + +#include +#include + +#include "adb.h" +#include "util/log.h" +#include "util/process_intr.h" + +#define DEFAULT_PUSH_TARGET "/sdcard/Download/" + +static void +sc_file_pusher_request_destroy(struct sc_file_pusher_request *req) { + free(req->file); +} + +bool +sc_file_pusher_init(struct sc_file_pusher *fp, const char *serial, + const char *push_target) { + assert(serial); + + cbuf_init(&fp->queue); + + bool ok = sc_mutex_init(&fp->mutex); + if (!ok) { + return false; + } + + ok = sc_cond_init(&fp->event_cond); + if (!ok) { + sc_mutex_destroy(&fp->mutex); + return false; + } + + ok = sc_intr_init(&fp->intr); + if (!ok) { + sc_cond_destroy(&fp->event_cond); + sc_mutex_destroy(&fp->mutex); + return false; + } + + fp->serial = strdup(serial); + if (!fp->serial) { + LOG_OOM(); + sc_intr_destroy(&fp->intr); + sc_cond_destroy(&fp->event_cond); + sc_mutex_destroy(&fp->mutex); + return false; + } + + // lazy initialization + fp->initialized = false; + + fp->stopped = false; + + fp->push_target = push_target ? push_target : DEFAULT_PUSH_TARGET; + + return true; +} + +void +sc_file_pusher_destroy(struct sc_file_pusher *fp) { + sc_cond_destroy(&fp->event_cond); + sc_mutex_destroy(&fp->mutex); + sc_intr_destroy(&fp->intr); + free(fp->serial); + + struct sc_file_pusher_request req; + while (cbuf_take(&fp->queue, &req)) { + sc_file_pusher_request_destroy(&req); + } +} + +bool +sc_file_pusher_request(struct sc_file_pusher *fp, + enum sc_file_pusher_action action, char *file) { + // start file_pusher if it's used for the first time + if (!fp->initialized) { + if (!sc_file_pusher_start(fp)) { + return false; + } + fp->initialized = true; + } + + LOGI("Request to %s %s", action == SC_FILE_PUSHER_ACTION_INSTALL_APK + ? "install" : "push", + file); + struct sc_file_pusher_request req = { + .action = action, + .file = file, + }; + + sc_mutex_lock(&fp->mutex); + bool was_empty = cbuf_is_empty(&fp->queue); + bool res = cbuf_push(&fp->queue, req); + if (was_empty) { + sc_cond_signal(&fp->event_cond); + } + sc_mutex_unlock(&fp->mutex); + return res; +} + +static int +run_file_pusher(void *data) { + struct sc_file_pusher *fp = data; + struct sc_intr *intr = &fp->intr; + + const char *serial = fp->serial; + assert(serial); + + const char *push_target = fp->push_target; + assert(push_target); + + for (;;) { + sc_mutex_lock(&fp->mutex); + while (!fp->stopped && cbuf_is_empty(&fp->queue)) { + sc_cond_wait(&fp->event_cond, &fp->mutex); + } + if (fp->stopped) { + // stop immediately, do not process further events + sc_mutex_unlock(&fp->mutex); + break; + } + struct sc_file_pusher_request req; + bool non_empty = cbuf_take(&fp->queue, &req); + assert(non_empty); + (void) non_empty; + sc_mutex_unlock(&fp->mutex); + + if (req.action == SC_FILE_PUSHER_ACTION_INSTALL_APK) { + LOGI("Installing %s...", req.file); + bool ok = adb_install(intr, serial, req.file, 0); + if (ok) { + LOGI("%s successfully installed", req.file); + } else { + LOGE("Failed to install %s", req.file); + } + } else { + LOGI("Pushing %s...", req.file); + bool ok = adb_push(intr, serial, req.file, push_target, 0); + if (ok) { + LOGI("%s successfully pushed to %s", req.file, push_target); + } else { + LOGE("Failed to push %s to %s", req.file, push_target); + } + } + + sc_file_pusher_request_destroy(&req); + } + return 0; +} + +bool +sc_file_pusher_start(struct sc_file_pusher *fp) { + LOGD("Starting file_pusher thread"); + + bool ok = sc_thread_create(&fp->thread, run_file_pusher, "scrcpy-file", fp); + if (!ok) { + LOGC("Could not start file_pusher thread"); + return false; + } + + return true; +} + +void +sc_file_pusher_stop(struct sc_file_pusher *fp) { + sc_mutex_lock(&fp->mutex); + fp->stopped = true; + sc_cond_signal(&fp->event_cond); + sc_intr_interrupt(&fp->intr); + sc_mutex_unlock(&fp->mutex); +} + +void +sc_file_pusher_join(struct sc_file_pusher *fp) { + sc_thread_join(&fp->thread, NULL); +} diff --git a/app/src/file_pusher.h b/app/src/file_pusher.h new file mode 100644 index 00000000..56b107a0 --- /dev/null +++ b/app/src/file_pusher.h @@ -0,0 +1,59 @@ +#ifndef SC_FILE_PUSHER_H +#define SC_FILE_PUSHER_H + +#include "common.h" + +#include + +#include "adb.h" +#include "util/cbuf.h" +#include "util/thread.h" +#include "util/intr.h" + +enum sc_file_pusher_action { + SC_FILE_PUSHER_ACTION_INSTALL_APK, + SC_FILE_PUSHER_ACTION_PUSH_FILE, +}; + +struct sc_file_pusher_request { + enum sc_file_pusher_action action; + char *file; +}; + +struct sc_file_pusher_request_queue CBUF(struct sc_file_pusher_request, 16); + +struct sc_file_pusher { + char *serial; + const char *push_target; + sc_thread thread; + sc_mutex mutex; + sc_cond event_cond; + bool stopped; + bool initialized; + struct sc_file_pusher_request_queue queue; + + struct sc_intr intr; +}; + +bool +sc_file_pusher_init(struct sc_file_pusher *fp, const char *serial, + const char *push_target); + +void +sc_file_pusher_destroy(struct sc_file_pusher *fp); + +bool +sc_file_pusher_start(struct sc_file_pusher *fp); + +void +sc_file_pusher_stop(struct sc_file_pusher *fp); + +void +sc_file_pusher_join(struct sc_file_pusher *fp); + +// take ownership of file, and will free() it +bool +sc_file_pusher_request(struct sc_file_pusher *fp, + enum sc_file_pusher_action action, char *file); + +#endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index e55fef80..4e7ccd6f 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -16,7 +16,7 @@ #include "controller.h" #include "decoder.h" #include "events.h" -#include "file_handler.h" +#include "file_pusher.h" #ifdef HAVE_AOA_HID # include "hid_keyboard.h" # include "hid_mouse.h" @@ -44,7 +44,7 @@ struct scrcpy { struct sc_v4l2_sink v4l2_sink; #endif struct sc_controller controller; - struct file_handler file_handler; + struct sc_file_pusher file_pusher; #ifdef HAVE_AOA_HID struct sc_aoa aoa; // sequence/ack helper to synchronize clipboard and Ctrl+v via HID @@ -181,13 +181,13 @@ handle_event(struct scrcpy *s, const struct scrcpy_options *options, break; } - file_handler_action_t action; + enum sc_file_pusher_action action; if (is_apk(file)) { - action = ACTION_INSTALL_APK; + action = SC_FILE_PUSHER_ACTION_INSTALL_APK; } else { - action = ACTION_PUSH_FILE; + action = SC_FILE_PUSHER_ACTION_PUSH_FILE; } - file_handler_request(&s->file_handler, action, file); + sc_file_pusher_request(&s->file_pusher, action, file); goto end; } } @@ -327,7 +327,7 @@ scrcpy(struct scrcpy_options *options) { bool ret = false; bool server_started = false; - bool file_handler_initialized = false; + bool file_pusher_initialized = false; bool recorder_initialized = false; #ifdef HAVE_V4L2 bool v4l2_sink_initialized = false; @@ -408,11 +408,11 @@ scrcpy(struct scrcpy_options *options) { assert(serial); if (options->display && options->control) { - if (!file_handler_init(&s->file_handler, serial, - options->push_target)) { + if (!sc_file_pusher_init(&s->file_pusher, serial, + options->push_target)) { goto end; } - file_handler_initialized = true; + file_pusher_initialized = true; } struct decoder *dec = NULL; @@ -649,8 +649,8 @@ end: if (controller_started) { sc_controller_stop(&s->controller); } - if (file_handler_initialized) { - file_handler_stop(&s->file_handler); + if (file_pusher_initialized) { + sc_file_pusher_stop(&s->file_pusher); } if (screen_initialized) { sc_screen_interrupt(&s->screen); @@ -698,9 +698,9 @@ end: recorder_destroy(&s->recorder); } - if (file_handler_initialized) { - file_handler_join(&s->file_handler); - file_handler_destroy(&s->file_handler); + if (file_pusher_initialized) { + sc_file_pusher_join(&s->file_pusher); + sc_file_pusher_destroy(&s->file_pusher); } sc_server_destroy(&s->server);