diff --git a/BUILD.md b/BUILD.md index db517c45..9c845215 100644 --- a/BUILD.md +++ b/BUILD.md @@ -43,7 +43,7 @@ Install the required packages from your package manager. sudo apt install ffmpeg libsdl2-2.0.0 # client build dependencies -sudo apt install make gcc pkg-config meson \ +sudo apt install make gcc pkg-config meson ninja-build \ libavcodec-dev libavformat-dev libavutil-dev \ libsdl2-dev @@ -199,6 +199,12 @@ cd x ninja ``` +_Note: `ninja` [must][ninja-user] be run as a non-root user (only `ninja +install` must be run as root)._ + +[ninja-user]: https://github.com/Genymobile/scrcpy/commit/4c49b27e9f6be02b8e63b508b60535426bd0291a + + ### Run To run without installing: @@ -229,9 +235,9 @@ You can then [run](README.md#run) _scrcpy_. ## Prebuilt server - [`scrcpy-server-v1.5.jar`][direct-scrcpy-server] - _(SHA-256: c827f566172a5c5946e63b8378ac93d374dff9e229083e5cd9980df57536947b)_ + _(SHA-256: d97aab6f60294e33e7ff79c2856ad3e01f912892395131f4f337e9ece03c24de)_ -[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-server-v1.5.jar +[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-server-v1.5.jar Download the prebuilt server somewhere, and specify its path during the Meson configuration: diff --git a/README.md b/README.md index 3b50401a..388c7f52 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,11 @@ Make sure you [enabled adb debugging][enable-adb] on your device(s). [enable-adb]: https://developer.android.com/studio/command-line/adb.html#Enabling +On some devices, you also need to enable [an additional option][control] to +control it using keyboard and mouse. + +[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323 + ## Get the app @@ -43,12 +48,12 @@ For Windows, for simplicity, prebuilt archives with all the dependencies (including `adb`) are available: - [`scrcpy-win32-v1.5.zip`][direct-win32] - _(SHA-256: 9118d74655a3e2daf9c1db37caf578f0b5239ccb078dbcbdb451e8a0becfe19f)_ + _(SHA-256: 46ae0d4c1c6bd049ec4a30080d2ad91a32b31d3f758afdca2c3a915ecabf02c1)_ - [`scrcpy-win64-v1.5.zip`][direct-win64] - _(SHA-256: fcaf7d596e8829cbcc119d67ec055eef2ee14ee204f28b33b7794f225ce16463)_ + _(SHA-256: 89daa07325129617cf943a84bc4e304ee5e57118416fe265b9b5d4a1bf87c501)_ -[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-win32-v1.5.zip -[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.5/scrcpy-win64-v1.5.zip +[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-win32-v1.5.zip +[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.5-fixversion/scrcpy-win64-v1.5.zip You can also [build the app manually][BUILD]. @@ -208,6 +213,22 @@ scrcpy -t Note that it only shows _physical_ touches (with the finger on the device). +### Install APK + +To install an APK, drag & drop an APK file (ending with `.apk`) to the _scrcpy_ +window. + +There is no visual feedback, a log is printed to the console. + + +### Push file to device + +To push a file to `/sdcard/` on the device, drag & drop a (non-APK) file to the +_scrcpy_ window. + +There is no visual feedback, a log is printed to the console. + + ### Forward audio Audio is not forwarded by _scrcpy_. @@ -238,8 +259,6 @@ you are interested, see [issue 14]. | turn screen on | _Right-click²_ | | paste computer clipboard to device | `Ctrl`+`v` | | enable/disable FPS counter (on stdout) | `Ctrl`+`i` | - | install APK from computer | drag & drop APK file | - | push file to `/sdcard/` | drag & drop non-APK file | _¹Double-click on black borders to remove them._ _²Right-click turns the screen on if it was off, presses BACK otherwise._ diff --git a/app/meson.build b/app/meson.build index 07122a24..3286fde1 100644 --- a/app/meson.build +++ b/app/meson.build @@ -86,7 +86,7 @@ conf = configuration_data() conf.set('BUILD_DEBUG', get_option('buildtype') == 'debug') # the version, updated on release -conf.set_quoted('SCRCPY_VERSION', '1.4') +conf.set_quoted('SCRCPY_VERSION', meson.project_version()) # the prefix used during configuration (meson --prefix=PREFIX) conf.set_quoted('PREFIX', get_option('prefix')) diff --git a/app/src/decoder.c b/app/src/decoder.c index 7e1e041d..fd429147 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -80,12 +80,15 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { if (!state->remaining) { #define HEADER_SIZE 12 uint8_t header[HEADER_SIZE]; - ssize_t ret = net_recv_all(decoder->video_socket, header, HEADER_SIZE); - if (ret <= 0) { - return ret; + ssize_t r = net_recv_all(decoder->video_socket, header, HEADER_SIZE); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; } // no partial read (net_recv_all()) - SDL_assert_release(ret == HEADER_SIZE); + SDL_assert_release(r == HEADER_SIZE); uint64_t pts = buffer_read64be(header); state->remaining = buffer_read32be(&header[8]); @@ -93,7 +96,7 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { if (pts != NO_PTS && !receiver_state_push_meta(state, pts)) { LOGE("Could not store PTS for recording"); // we cannot save the PTS, the recording would be broken - return -1; + return AVERROR(ENOMEM); } } @@ -102,20 +105,30 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { if (buf_size > state->remaining) buf_size = state->remaining; - ssize_t ret = net_recv(decoder->video_socket, buf, buf_size); - if (ret <= 0) { - return ret; + ssize_t r = net_recv(decoder->video_socket, buf, buf_size); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; } - SDL_assert(state->remaining >= ret); - state->remaining -= ret; + SDL_assert(state->remaining >= r); + state->remaining -= r; - return ret; + return r; } static int read_raw_packet(void *opaque, uint8_t *buf, int buf_size) { struct decoder *decoder = opaque; - return net_recv(decoder->video_socket, buf, buf_size); + ssize_t r = net_recv(decoder->video_socket, buf, buf_size); + if (r == -1) { + return AVERROR(errno); + } + if (r == 0) { + return AVERROR_EOF; + } + return r; } // set the decoded frame as ready for rendering, and notify diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 21b7c407..7a3a4ad1 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -18,16 +18,9 @@ static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y = (int) (*y / scale_y) - viewport.y; } -static struct point get_mouse_point(struct screen *screen) { - int x; - int y; - SDL_GetMouseState(&x, &y); - convert_to_renderer_coordinates(screen->renderer, &x, &y); - SDL_assert_release(x >= 0 && x < 0x10000 && y >= 0 && y < 0x10000); - return (struct point) { - .x = (Uint16) x, - .y = (Uint16) y, - }; +static void get_mouse_point(struct screen *screen, int *x, int *y) { + SDL_GetMouseState(x, y); + convert_to_renderer_coordinates(screen->renderer, x, y); } static const int ACTION_DOWN = 1; @@ -271,8 +264,18 @@ void input_manager_process_mouse_motion(struct input_manager *input_manager, } } +static SDL_bool is_outside_device_screen(struct input_manager *input_manager, + int x, int y) +{ + return x < 0 || x >= input_manager->screen->frame_size.width || + y < 0 || y >= input_manager->screen->frame_size.height; +} + void input_manager_process_mouse_button(struct input_manager *input_manager, const SDL_MouseButtonEvent *event) { + SDL_bool outside_device_screen = is_outside_device_screen(input_manager, + event->x, + event->y); if (event->type == SDL_MOUSEBUTTONDOWN) { if (event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); @@ -283,17 +286,19 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, return; } // double-click on black borders resize to fit the device screen - if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { - SDL_bool outside_device_screen = - event->x < 0 || event->x >= input_manager->screen->frame_size.width || - event->y < 0 || event->y >= input_manager->screen->frame_size.height; - if (outside_device_screen) { - screen_resize_to_fit(input_manager->screen); - return; - } - // otherwise, send the click event to the device + if (event->button == SDL_BUTTON_LEFT && event->clicks == 2 + && outside_device_screen) { + screen_resize_to_fit(input_manager->screen); + return; } + // otherwise, send the click event to the device } + + if (outside_device_screen) { + // ignore + return; + } + struct control_event control_event; if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, &control_event)) { if (!controller_push_event(input_manager->controller, &control_event)) { @@ -304,9 +309,22 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, void input_manager_process_mouse_wheel(struct input_manager *input_manager, const SDL_MouseWheelEvent *event) { + int x; + int y; + get_mouse_point(input_manager->screen, &x, &y); + if (is_outside_device_screen(input_manager, x, y)) { + // ignore + return; + } + + SDL_assert_release(x >= 0 && x < 0x10000 && y >= 0 && y < 0x10000); + struct position position = { .screen_size = input_manager->screen->frame_size, - .point = get_mouse_point(input_manager->screen), + .point = { + .x = (Uint16) x, + .y = (Uint16) y, + }, }; struct control_event control_event; if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) { diff --git a/app/src/main.c b/app/src/main.c index 65887295..0603fef5 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -124,7 +124,7 @@ static void usage(const char *arg0) { } static void print_version(void) { - fprintf(stderr, "scrcpy v%s\n\n", SCRCPY_VERSION); + fprintf(stderr, "scrcpy %s\n\n", SCRCPY_VERSION); fprintf(stderr, "dependencies:\n"); fprintf(stderr, " - SDL %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); diff --git a/meson.build b/meson.build index 2f9ec462..fdac788e 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,7 @@ -project('scrcpy', 'c', meson_version: '>= 0.37', default_options : 'c_std=c11') +project('scrcpy', 'c', + version: '1.5', + meson_version: '>= 0.37', + default_options: 'c_std=c11') if get_option('build_app') subdir('app') diff --git a/server/build.gradle b/server/build.gradle index 957a61d7..c082e8bd 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.genymobile.scrcpy" minSdkVersion 21 targetSdkVersion 27 - versionCode 5 - versionName "1.4" + versionCode 6 + versionName "1.5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes {