Compare commits

..

2 Commits

Author SHA1 Message Date
Romain Vimont
d82db2e69e Do not explicitly kill server
Let the server terminate properly once all the sockets are closed.

Fixes #1992 <https://github.com/Genymobile/scrcpy/issues/1992>
2021-01-01 12:43:42 +01:00
Romain Vimont
305b4b2b81 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 12:43:32 +01:00
20 changed files with 57 additions and 152 deletions

36
FAQ.md
View File

@@ -201,39 +201,3 @@ scrcpy -m 800
``` ```
You could also try another [encoder](README.md#encoder). 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. identification within third-party archives.
Copyright (C) 2018 Genymobile Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 Romain Vimont Copyright (C) 2018-2020 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

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

View File

@@ -202,8 +202,6 @@ scrcpy --lock-video-orientation 3 # 90° clockwise
This affects recording orientation. This affects recording orientation.
The [window may also be rotated](#rotation) independently.
#### Encoder #### Encoder
@@ -409,9 +407,9 @@ Note that _scrcpy_ manages 3 different rotations:
- <kbd>MOD</kbd>+<kbd>r</kbd> requests the device to switch between portrait - <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 and landscape (the current running app may refuse, if it does support the
requested orientation). requested orientation).
- [`--lock-video-orientation`](#lock-video-orientation) changes the mirroring - `--lock-video-orientation` changes the mirroring orientation (the orientation
orientation (the orientation of the video sent from the device to the of the video sent from the device to the computer). This affects the
computer). This affects the recording. recording.
- `--rotation` (or <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>) - `--rotation` (or <kbd>MOD</kbd>+<kbd>←</kbd>/<kbd>MOD</kbd>+<kbd>→</kbd>)
rotates only the window content. This affects only the display, not the rotates only the window content. This affects only the display, not the
recording. recording.
@@ -768,7 +766,7 @@ Read the [developers page].
## Licence ## Licence
Copyright (C) 2018 Genymobile Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 Romain Vimont Copyright (C) 2018-2020 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 ## Licença
Copyright (C) 2018 Genymobile Copyright (C) 2018 Genymobile
Copyright (C) 2018-2021 Romain Vimont Copyright (C) 2018-2020 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 Genymobile
Copyright (C) 2018-2021 Romain Vimont Copyright (C) 2018-2020 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

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

View File

@@ -34,7 +34,7 @@
#include "util/log.h" #include "util/log.h"
#include "util/net.h" #include "util/net.h"
static struct server server; static struct server server = SERVER_INITIALIZER;
static struct screen screen = SCREEN_INITIALIZER; static struct screen screen = SCREEN_INITIALIZER;
static struct fps_counter fps_counter; static struct fps_counter fps_counter;
static struct video_buffer video_buffer; static struct video_buffer video_buffer;
@@ -304,19 +304,6 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
bool bool
scrcpy(const struct scrcpy_options *options) { scrcpy(const struct scrcpy_options *options) {
if (!server_init(&server)) {
return 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; bool record = !!options->record_filename;
struct server_params params = { struct server_params params = {
.log_level = options->log_level, .log_level = options->log_level,
@@ -335,10 +322,18 @@ scrcpy(const struct scrcpy_options *options) {
.force_adb_forward = options->force_adb_forward, .force_adb_forward = options->force_adb_forward,
}; };
if (!server_start(&server, options->serial, &params)) { if (!server_start(&server, options->serial, &params)) {
goto end; return false;
} }
server_started = true; 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;
if (!sdl_init_and_configure(options->display, options->render_driver, if (!sdl_init_and_configure(options->display, options->render_driver,
options->disable_screensaver)) { options->disable_screensaver)) {
@@ -449,7 +444,7 @@ scrcpy(const struct scrcpy_options *options) {
input_manager_init(&input_manager, options); input_manager_init(&input_manager, options);
bool ret = event_loop(options); ret = event_loop(options);
LOGD("quit..."); LOGD("quit...");
screen_destroy(&screen); screen_destroy(&screen);
@@ -470,10 +465,8 @@ end:
fps_counter_interrupt(&fps_counter); fps_counter_interrupt(&fps_counter);
} }
if (server_started) { // shutdown the sockets and kill the server
// shutdown the sockets and kill the server server_stop(&server);
server_stop(&server);
}
// now that the sockets are shutdown, the stream and controller are // now that the sockets are shutdown, the stream and controller are
// interrupted, we can join them // interrupted, we can join them

View File

@@ -11,7 +11,6 @@
#include "config.h" #include "config.h"
#include "command.h" #include "command.h"
#include "util/lock.h"
#include "util/log.h" #include "util/log.h"
#include "util/net.h" #include "util/net.h"
#include "util/str_util.h" #include "util/str_util.h"
@@ -354,51 +353,15 @@ close_socket(socket_t socket) {
} }
} }
bool void
server_init(struct server *server) { server_init(struct server *server) {
server->serial = NULL; *server = (struct server) SERVER_INITIALIZER;
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 static int
run_wait_server(void *data) { run_wait_server(void *data) {
struct server *server = data; struct server *server = data;
cmd_simple_wait(server->process, NULL); // ignore exit code 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 // no need for synchronization, server_socket is initialized before this
// thread was created // thread was created
if (server->server_socket != INVALID_SOCKET if (server->server_socket != INVALID_SOCKET
@@ -535,34 +498,10 @@ server_stop(struct server *server) {
disable_tunnel(server); 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); SDL_WaitThread(server->wait_server_thread, NULL);
} }
void void
server_destroy(struct server *server) { server_destroy(struct server *server) {
SDL_free(server->serial); SDL_free(server->serial);
SDL_DestroyCond(server->process_terminated_cond);
SDL_DestroyMutex(server->mutex);
} }

View File

@@ -18,11 +18,6 @@ struct server {
process_t process; process_t process;
SDL_Thread *wait_server_thread; SDL_Thread *wait_server_thread;
atomic_flag server_socket_closed; 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 server_socket; // only used if !tunnel_forward
socket_t video_socket; socket_t video_socket;
socket_t control_socket; socket_t control_socket;
@@ -32,6 +27,23 @@ struct server {
bool tunnel_forward; // use "adb forward" instead of "adb reverse" 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 { struct server_params {
enum sc_log_level log_level; enum sc_log_level log_level;
const char *crop; const char *crop;
@@ -50,7 +62,7 @@ struct server_params {
}; };
// init default values // init default values
bool void
server_init(struct server *server); server_init(struct server *server);
// push, enable tunnel et start the server // push, enable tunnel et start the server

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,9 +30,9 @@ prepare-ffmpeg-dev-win64:
ffmpeg-4.3.1-win64-dev ffmpeg-4.3.1-win64-dev
prepare-sdl2: prepare-sdl2:
@./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.14-mingw.tar.gz \ @./prepare-dep https://libsdl.org/release/SDL2-devel-2.0.12-mingw.tar.gz \
405eaff3eb18f2e08fe669ef9e63bc9a8710b7d343756f238619761e9b60407d \ e614a60f797e35ef9f3f96aef3dc6a1d786de3cc7ca6216f97e435c0b6aafc46 \
SDL2-2.0.14 SDL2-2.0.12
prepare-adb: prepare-adb:
@./prepare-dep https://dl.google.com/android/repository/platform-tools_r30.0.5-windows.zip \ @./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/adb.exe "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(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/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.14/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/" cp prebuilt-deps/SDL2-2.0.12/i686-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN32_TARGET_DIR)/"
dist-win64: build-server build-win64 dist-win64: build-server build-win64
mkdir -p "$(DIST)/$(WIN64_TARGET_DIR)" 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/adb.exe "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/platform-tools/AdbWinApi.dll "$(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/platform-tools/AdbWinUsbApi.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
cp prebuilt-deps/SDL2-2.0.14/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/" cp prebuilt-deps/SDL2-2.0.12/x86_64-w64-mingw32/bin/SDL2.dll "$(DIST)/$(WIN64_TARGET_DIR)/"
zip-win32: dist-win32 zip-win32: dist-win32
cd "$(DIST)/$(WIN32_TARGET_DIR)"; \ cd "$(DIST)/$(WIN32_TARGET_DIR)"; \

View File

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

View File

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

View File

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