Compare commits

...

16 Commits

Author SHA1 Message Date
Romain Vimont
aa8b571389 Increase display id range
Some devices use big display id values.

Refs #2009 <https://github.com/Genymobile/scrcpy/issues/2009>
2021-01-04 08:16:32 +01:00
Romain Vimont
ed130e05d5 Fix possibly uninitialized value
Due to gotos, "ret" may be returned uninitialized.
2021-01-03 22:41:51 +01:00
clesiemo3
192fbd8450 Use --cask for latest versions of brew
PR #2004 <https://github.com/Genymobile/scrcpy/pull/2004>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2021-01-02 18:27:38 +01:00
Romain Vimont
c5c5fc18ae Update links to v1.17 in README and BUILD 2021-01-02 01:26:23 +01:00
Romain Vimont
f682b87ba5 Bump version to 1.17 2021-01-02 00:53:32 +01:00
Romain Vimont
10b749e27d Kill the server only after a small delay
Let the server terminate properly once all the sockets are closed.

If it does not terminate (this can happen if the device is asleep), then
kill it.

Note: since the server process termination is detected by a flag set
after waitpid() returns, there is a small chance that the process
terminates (and the PID assigned to a new process) before the flag is
set but before the kill() call. This race condition already existed
before this commit.

Fixes #1992 <https://github.com/Genymobile/scrcpy/issues/1992>
2021-01-01 23:57:01 +01:00
Romain Vimont
05e8c1a3c5 Call CloseHandle() after wait on Windows
TerminateProcess() is "equivalent" to kill(), while
WaitForSingleObject() is "equivalent" to waitpid(), so the handle must
be closed after WaitForSingleObject().
2021-01-01 23:57:01 +01:00
Romain Vimont
83910d3b9c Initialize server struct dynamically
This will allow to add mutex/cond fields.
2021-01-01 17:40:52 +01:00
Romain Vimont
90f8356630 Interrupt device threads on stop
The (non-daemon) threads were not interrupted on video stream stopped,
leaving the server process alive.

Interrupt them to wake up their blocking call so that they terminate
properly.

Refs #1992 <https://github.com/Genymobile/scrcpy/issues/1992>
2021-01-01 17:32:34 +01:00
Romain Vimont
3ba51211d6 Mention how to add default arguments on Windows
Mention that it is possible to add default arguments by editing the
wrapper scripts.
2021-01-01 17:31:07 +01:00
Romain Vimont
ea3582d2c3 Merge branch 'master' into dev 2021-01-01 17:18:13 +01:00
Romain Vimont
112adbba87 Happy new year 2021! 2021-01-01 17:16:44 +01:00
Romain Vimont
d039a7a39a Upgrade SDL (2.0.14) for Windows
Include the latest version of SDL in Windows releases.
2021-01-01 16:08:58 +01:00
Romain Vimont
6ab80e4ce8 Rename release.make to release.mk
It's more standard, and benefits from syntax coloration in vi.
2021-01-01 15:51:10 +01:00
Romain Vimont
431c9ee33b Improve rotation documentation 2020-12-22 01:48:01 +01:00
Romain Vimont
43d3dcbd97 Document Windows command line usage
PR #1973 <https://github.com/Genymobile/scrcpy/pull/1973>

Reviewed-by: Yu-Chen Lin <npes87184@gmail.com>
2020-12-22 01:44:55 +01:00
24 changed files with 192 additions and 80 deletions

View File

@@ -254,10 +254,10 @@ You can then [run](README.md#run) _scrcpy_.
## Prebuilt server
- [`scrcpy-server-v1.16`][direct-scrcpy-server]
_(SHA-256: 94a79e05b4498d0460ab7bd9d12cbf05156e3a47bf0c5d1420cee1d4493b3832)_
- [`scrcpy-server-v1.17`][direct-scrcpy-server]
_(SHA-256: 11b5ad2d1bc9b9730fb7254a78efd71a8ff46b1938ff468e47a21b653a1b6725_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-server-v1.16
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-server-v1.17
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:

36
FAQ.md
View File

@@ -201,3 +201,39 @@ scrcpy -m 800
```
You could also try another [encoder](README.md#encoder).
## Command line on Windows
Some Windows users are not familiar with the command line. Here is how to open a
terminal and run `scrcpy` with arguments:
1. Press <kbd>Windows</kbd>+<kbd>r</kbd>, this opens a dialog box.
2. Type `cmd` and press <kbd>Enter</kbd>, this opens a terminal.
3. Go to your _scrcpy_ directory, by typing (adapt the path):
```bat
cd C:\Users\user\Downloads\scrcpy-win64-xxx
```
and press <kbd>Enter</kbd>
4. Type your command. For example:
```bat
scrcpy --record file.mkv
```
If you plan to always use the same arguments, create a file `myscrcpy.bat`
(enable [show file extensions] to avoid confusion) in the `scrcpy` directory,
containing your command. For example:
```bat
scrcpy --prefer-text --turn-screen-off --stay-awake
```
Then just double-click on that file.
You could also edit (a copy of) `scrcpy-console.bat` or `scrcpy-noconsole.vbs`
to add some arguments.
[show file extensions]: https://www.howtogeek.com/205086/beginner-how-to-make-windows-show-file-extensions/

View File

@@ -188,7 +188,7 @@
identification within third-party archives.
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -675,7 +675,7 @@ Baca [halaman pengembang].
## Lisensi
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -477,7 +477,7 @@ _²화면이 꺼진 상태에서 우클릭 시 다시 켜지며, 그 외의 상
## 라이선스
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
# scrcpy (v1.16)
# scrcpy (v1.17)
[Read in another language](#translations)
@@ -77,10 +77,10 @@ hard).
For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available:
- [`scrcpy-win64-v1.16.zip`][direct-win64]
_(SHA-256: 3f30dc5db1a2f95c2b40a0f5de91ec1642d9f53799250a8c529bc882bc0918f0)_
- [`scrcpy-win64-v1.17.zip`][direct-win64]
_(SHA-256: 8b9e57993c707367ed10ebfe0e1ef563c7a29d9af4a355cd8b6a52a317c73eea)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.16/scrcpy-win64-v1.16.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.17/scrcpy-win64-v1.17.zip
It is also available in [Chocolatey]:
@@ -116,6 +116,10 @@ brew install scrcpy
You need `adb`, accessible from your `PATH`. If you don't have it yet:
```bash
# Homebrew >= 2.6.0
brew install --cask android-platform-tools
# Homebrew < 2.6.0
brew cask install android-platform-tools
```
@@ -202,6 +206,8 @@ scrcpy --lock-video-orientation 3 # 90° clockwise
This affects recording orientation.
The [window may also be rotated](#rotation) independently.
#### Encoder
@@ -407,9 +413,9 @@ Note that _scrcpy_ manages 3 different rotations:
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait
and landscape (the current running app may refuse, if it does support the
requested orientation).
- `--lock-video-orientation` changes the mirroring orientation (the orientation
of the video sent from the device to the computer). This affects the
recording.
- [`--lock-video-orientation`](#lock-video-orientation) changes the mirroring
orientation (the orientation of the video sent from the device to the
computer). This affects the recording.
- `--rotation` (or <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
rotates only the window content. This affects only the display, not the
recording.
@@ -766,7 +772,7 @@ Read the [developers page].
## Licence
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -508,7 +508,7 @@ Leia a [developers page].
## Licença
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -703,7 +703,7 @@ _³需要安卓版本 Android >= 7。_
## 许可协议
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -682,7 +682,7 @@ _³只支援 Android 7+。_
## Licence
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2020 Romain Vimont
Copyright (C) 2018-2021 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -478,14 +478,14 @@ parse_port_range(const char *s, struct sc_port_range *port_range) {
}
static bool
parse_display_id(const char *s, uint16_t *display_id) {
parse_display_id(const char *s, uint32_t *display_id) {
long value;
bool ok = parse_integer_arg(s, &value, false, 0, 0xFFFF, "display id");
bool ok = parse_integer_arg(s, &value, false, 0, 0x7FFFFFFF, "display id");
if (!ok) {
return false;
}
*display_id = (uint16_t) value;
*display_id = (uint32_t) value;
return true;
}

View File

@@ -34,7 +34,7 @@
#include "util/log.h"
#include "util/net.h"
static struct server server = SERVER_INITIALIZER;
static struct server server;
static struct screen screen = SCREEN_INITIALIZER;
static struct fps_counter fps_counter;
static struct video_buffer video_buffer;
@@ -304,6 +304,21 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
bool
scrcpy(const struct scrcpy_options *options) {
if (!server_init(&server)) {
return false;
}
bool ret = false;
bool server_started = false;
bool fps_counter_initialized = false;
bool video_buffer_initialized = false;
bool file_handler_initialized = false;
bool recorder_initialized = false;
bool stream_started = false;
bool controller_initialized = false;
bool controller_started = false;
bool record = !!options->record_filename;
struct server_params params = {
.log_level = options->log_level,
@@ -322,18 +337,10 @@ scrcpy(const struct scrcpy_options *options) {
.force_adb_forward = options->force_adb_forward,
};
if (!server_start(&server, options->serial, &params)) {
return false;
goto end;
}
bool ret = false;
bool fps_counter_initialized = false;
bool video_buffer_initialized = false;
bool file_handler_initialized = false;
bool recorder_initialized = false;
bool stream_started = false;
bool controller_initialized = false;
bool controller_started = false;
server_started = true;
if (!sdl_init_and_configure(options->display, options->render_driver,
options->disable_screensaver)) {
@@ -465,8 +472,10 @@ end:
fps_counter_interrupt(&fps_counter);
}
// shutdown the sockets and kill the server
server_stop(&server);
if (server_started) {
// shutdown the sockets and kill the server
server_stop(&server);
}
// now that the sockets are shutdown, the stream and controller are
// interrupted, we can join them

View File

@@ -65,7 +65,7 @@ struct scrcpy_options {
int16_t window_y; // SC_WINDOW_POSITION_UNDEFINED for "auto"
uint16_t window_width;
uint16_t window_height;
uint16_t display_id;
uint32_t display_id;
bool show_touches;
bool fullscreen;
bool always_on_top;

View File

@@ -11,6 +11,7 @@
#include "config.h"
#include "command.h"
#include "util/lock.h"
#include "util/log.h"
#include "util/net.h"
#include "util/str_util.h"
@@ -257,12 +258,12 @@ execute_server(struct server *server, const struct server_params *params) {
char bit_rate_string[11];
char max_fps_string[6];
char lock_video_orientation_string[5];
char display_id_string[6];
char display_id_string[11];
sprintf(max_size_string, "%"PRIu16, params->max_size);
sprintf(bit_rate_string, "%"PRIu32, params->bit_rate);
sprintf(max_fps_string, "%"PRIu16, params->max_fps);
sprintf(lock_video_orientation_string, "%"PRIi8, params->lock_video_orientation);
sprintf(display_id_string, "%"PRIu16, params->display_id);
sprintf(display_id_string, "%"PRIu32, params->display_id);
const char *const cmd[] = {
"shell",
"CLASSPATH=" DEVICE_SERVER_PATH,
@@ -353,15 +354,51 @@ close_socket(socket_t socket) {
}
}
void
bool
server_init(struct server *server) {
*server = (struct server) SERVER_INITIALIZER;
server->serial = NULL;
server->process = PROCESS_NONE;
server->wait_server_thread = NULL;
atomic_flag_clear_explicit(&server->server_socket_closed,
memory_order_relaxed);
server->mutex = SDL_CreateMutex();
if (!server->mutex) {
return false;
}
server->process_terminated_cond = SDL_CreateCond();
if (!server->process_terminated_cond) {
SDL_DestroyMutex(server->mutex);
return false;
}
server->process_terminated = false;
server->server_socket = INVALID_SOCKET;
server->video_socket = INVALID_SOCKET;
server->control_socket = INVALID_SOCKET;
server->port_range.first = 0;
server->port_range.last = 0;
server->local_port = 0;
server->tunnel_enabled = false;
server->tunnel_forward = false;
return true;
}
static int
run_wait_server(void *data) {
struct server *server = data;
cmd_simple_wait(server->process, NULL); // ignore exit code
mutex_lock(server->mutex);
server->process_terminated = true;
cond_signal(server->process_terminated_cond);
mutex_unlock(server->mutex);
// no need for synchronization, server_socket is initialized before this
// thread was created
if (server->server_socket != INVALID_SOCKET
@@ -493,17 +530,39 @@ server_stop(struct server *server) {
assert(server->process != PROCESS_NONE);
cmd_terminate(server->process);
if (server->tunnel_enabled) {
// ignore failure
disable_tunnel(server);
}
// Give some delay for the server to terminate properly
mutex_lock(server->mutex);
int r = 0;
if (!server->process_terminated) {
#define WATCHDOG_DELAY_MS 1000
r = cond_wait_timeout(server->process_terminated_cond,
server->mutex,
WATCHDOG_DELAY_MS);
}
mutex_unlock(server->mutex);
// After this delay, kill the server if it's not dead already.
// On some devices, closing the sockets is not sufficient to wake up the
// blocking calls while the device is asleep.
if (r == SDL_MUTEX_TIMEDOUT) {
// FIXME There is a race condition here: there is a small chance that
// the process is already terminated, and the PID assigned to a new
// process.
LOGW("Killing the server...");
cmd_terminate(server->process);
}
SDL_WaitThread(server->wait_server_thread, NULL);
}
void
server_destroy(struct server *server) {
SDL_free(server->serial);
SDL_DestroyCond(server->process_terminated_cond);
SDL_DestroyMutex(server->mutex);
}

View File

@@ -18,6 +18,11 @@ struct server {
process_t process;
SDL_Thread *wait_server_thread;
atomic_flag server_socket_closed;
SDL_mutex *mutex;
SDL_cond *process_terminated_cond;
bool process_terminated;
socket_t server_socket; // only used if !tunnel_forward
socket_t video_socket;
socket_t control_socket;
@@ -27,23 +32,6 @@ struct server {
bool tunnel_forward; // use "adb forward" instead of "adb reverse"
};
#define SERVER_INITIALIZER { \
.serial = NULL, \
.process = PROCESS_NONE, \
.wait_server_thread = NULL, \
.server_socket_closed = ATOMIC_FLAG_INIT, \
.server_socket = INVALID_SOCKET, \
.video_socket = INVALID_SOCKET, \
.control_socket = INVALID_SOCKET, \
.port_range = { \
.first = 0, \
.last = 0, \
}, \
.local_port = 0, \
.tunnel_enabled = false, \
.tunnel_forward = false, \
}
struct server_params {
enum sc_log_level log_level;
const char *crop;
@@ -55,14 +43,14 @@ struct server_params {
uint16_t max_fps;
int8_t lock_video_orientation;
bool control;
uint16_t display_id;
uint32_t display_id;
bool show_touches;
bool stay_awake;
bool force_adb_forward;
};
// init default values
void
bool
server_init(struct server *server);
// push, enable tunnel et start the server

View File

@@ -56,7 +56,7 @@ cmd_execute(const char *const argv[], HANDLE *handle) {
bool
cmd_terminate(HANDLE handle) {
return TerminateProcess(handle, 1) && CloseHandle(handle);
return TerminateProcess(handle, 1);
}
bool
@@ -70,6 +70,7 @@ cmd_simple_wait(HANDLE handle, DWORD *exit_code) {
if (exit_code) {
*exit_code = code;
}
CloseHandle(handle);
return !code;
}

View File

@@ -17,4 +17,4 @@ endian = 'little'
[properties]
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win32-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win32-dev'
prebuilt_sdl2 = 'SDL2-2.0.12/i686-w64-mingw32'
prebuilt_sdl2 = 'SDL2-2.0.14/i686-w64-mingw32'

View File

@@ -17,4 +17,4 @@ endian = 'little'
[properties]
prebuilt_ffmpeg_shared = 'ffmpeg-4.3.1-win64-shared'
prebuilt_ffmpeg_dev = 'ffmpeg-4.3.1-win64-dev'
prebuilt_sdl2 = 'SDL2-2.0.12/x86_64-w64-mingw32'
prebuilt_sdl2 = 'SDL2-2.0.14/x86_64-w64-mingw32'

View File

@@ -1,5 +1,5 @@
project('scrcpy', 'c',
version: '1.16',
version: '1.17',
meson_version: '>= 0.48',
default_options: [
'c_std=c11',

View File

@@ -30,9 +30,9 @@ prepare-ffmpeg-dev-win64:
ffmpeg-4.3.1-win64-dev
prepare-sdl2:
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.12-mingw.tar.gz \
e614a60f797e35ef9f3f96aef3dc6a1d786de3cc7ca6216f97e435c0b6aafc46 \
SDL2-2.0.12
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.14-mingw.tar.gz \
405eaff3eb18f2e08fe669ef9e63bc9a8710b7d343756f238619761e9b60407d \
SDL2-2.0.14
prepare-adb:
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.5-windows.zip \

View File

@@ -102,7 +102,7 @@ dist-win32: build-server build-win32
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.12/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.14/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
dist-win64: build-server build-win64
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)"
@@ -118,7 +118,7 @@ dist-win64: build-server build-win64
cp prebuilt-deps/platform-tools/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.12/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.14/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \

View File

@@ -1,2 +1,2 @@
#!/bin/bash
make -f release.make
make -f release.mk

View File

@@ -6,8 +6,8 @@ android {
applicationId "com.genymobile.scrcpy"
minSdkVersion 21
targetSdkVersion 30
versionCode 19
versionName "1.16"
versionCode 20
versionName "1.17"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {

View File

@@ -12,7 +12,7 @@
set -e
SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=1.16
SCRCPY_VERSION_NAME=1.17
PLATFORM=${ANDROID_PLATFORM:-30}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-30.0.0}

View File

@@ -58,12 +58,14 @@ public final class Server {
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
options.getEncoderName());
Thread controllerThread = null;
Thread deviceMessageSenderThread = null;
if (options.getControl()) {
final Controller controller = new Controller(device, connection);
// asynchronous
startController(controller);
startDeviceMessageSender(controller.getSender());
controllerThread = startController(controller);
deviceMessageSenderThread = startDeviceMessageSender(controller.getSender());
device.setClipboardListener(new Device.ClipboardListener() {
@Override
@@ -79,12 +81,19 @@ public final class Server {
} catch (IOException e) {
// this is expected on close
Ln.d("Screen streaming stopped");
} finally {
if (controllerThread != null) {
controllerThread.interrupt();
}
if (deviceMessageSenderThread != null) {
deviceMessageSenderThread.interrupt();
}
}
}
}
private static void startController(final Controller controller) {
new Thread(new Runnable() {
private static Thread startController(final Controller controller) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
@@ -94,11 +103,13 @@ public final class Server {
Ln.d("Controller stopped");
}
}
}).start();
});
thread.start();
return thread;
}
private static void startDeviceMessageSender(final DeviceMessageSender sender) {
new Thread(new Runnable() {
private static Thread startDeviceMessageSender(final DeviceMessageSender sender) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
@@ -108,7 +119,9 @@ public final class Server {
Ln.d("Device message sender stopped");
}
}
}).start();
});
thread.start();
return thread;
}
private static Options createOptions(String... args) {