Compare commits
26 Commits
fix_build_
...
windows_dp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6312ea9c98 | ||
|
|
feb250a973 | ||
|
|
d049671908 | ||
|
|
0685c491cd | ||
|
|
892cfe943e | ||
|
|
29570ee819 | ||
|
|
cfcbc2ac21 | ||
|
|
2cb4e04209 | ||
|
|
878ffffc36 | ||
|
|
f0361fc8b3 | ||
|
|
b5d4ec61fc | ||
|
|
3ada5c51bc | ||
|
|
09c55b0f93 | ||
|
|
682a691173 | ||
|
|
ddb9396743 | ||
|
|
cabcbc2b15 | ||
|
|
80fe12a95f | ||
|
|
099c546580 | ||
|
|
dca2c5f94f | ||
|
|
90cf956f57 | ||
|
|
36c8778d2d | ||
|
|
ae90ef22db | ||
|
|
d80bc25eba | ||
|
|
daa06abd34 | ||
|
|
94702a4309 | ||
|
|
65fbec9643 |
@@ -49,9 +49,11 @@ conf.set('_XOPEN_SOURCE', '700')
|
|||||||
conf.set('_GNU_SOURCE', true)
|
conf.set('_GNU_SOURCE', true)
|
||||||
|
|
||||||
if host_machine.system() == 'windows'
|
if host_machine.system() == 'windows'
|
||||||
|
windows = import('windows')
|
||||||
src += [
|
src += [
|
||||||
'src/sys/win/file.c',
|
'src/sys/win/file.c',
|
||||||
'src/sys/win/process.c',
|
'src/sys/win/process.c',
|
||||||
|
windows.compile_resources('scrcpy-windows.rc'),
|
||||||
]
|
]
|
||||||
conf.set('_WIN32_WINNT', '0x0600')
|
conf.set('_WIN32_WINNT', '0x0600')
|
||||||
conf.set('WINVER', '0x0600')
|
conf.set('WINVER', '0x0600')
|
||||||
@@ -80,14 +82,16 @@ endif
|
|||||||
|
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
if not get_option('crossbuild_windows')
|
crossbuild_windows = meson.is_cross_build() and host_machine.system() == 'windows'
|
||||||
|
|
||||||
|
if not crossbuild_windows
|
||||||
|
|
||||||
# native build
|
# native build
|
||||||
dependencies = [
|
dependencies = [
|
||||||
dependency('libavformat'),
|
dependency('libavformat', version: '>= 57.33'),
|
||||||
dependency('libavcodec'),
|
dependency('libavcodec', version: '>= 57.37'),
|
||||||
dependency('libavutil'),
|
dependency('libavutil'),
|
||||||
dependency('sdl2'),
|
dependency('sdl2', version: '>= 2.0.5'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if v4l2_support
|
if v4l2_support
|
||||||
|
|||||||
9
app/scrcpy-windows.manifest
Normal file
9
app/scrcpy-windows.manifest
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
23
app/scrcpy-windows.rc
Normal file
23
app/scrcpy-windows.rc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <winuser.h>
|
||||||
|
|
||||||
|
0 ICON "../data/icon.ico"
|
||||||
|
1 RT_MANIFEST "scrcpy-windows.manifest"
|
||||||
|
2 VERSIONINFO
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904E4"
|
||||||
|
BEGIN
|
||||||
|
VALUE "FileDescription", "Display and control your Android device"
|
||||||
|
VALUE "InternalName", "scrcpy"
|
||||||
|
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||||
|
VALUE "OriginalFilename", "scrcpy.exe"
|
||||||
|
VALUE "ProductName", "scrcpy"
|
||||||
|
VALUE "ProductVersion", "1.21"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1252
|
||||||
|
END
|
||||||
|
END
|
||||||
10
app/scrcpy.1
10
app/scrcpy.1
@@ -413,11 +413,15 @@ Push file to device (see \fB\-\-push\-target\fR)
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B ADB
|
.B ADB
|
||||||
Specify the path to adb.
|
Path to adb.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B SCRCPY_ICON_PATH
|
||||||
|
Path to the program icon.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B SCRCPY_SERVER_PATH
|
.B SCRCPY_SERVER_PATH
|
||||||
Specify the path to server binary.
|
Path to the server binary.
|
||||||
|
|
||||||
|
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
@@ -442,7 +446,7 @@ Copyright \(co 2018 Genymobile
|
|||||||
Genymobile
|
Genymobile
|
||||||
.UE
|
.UE
|
||||||
|
|
||||||
Copyright \(co 2018\-2020
|
Copyright \(co 2018\-2021
|
||||||
.MT rom@rom1v.com
|
.MT rom@rom1v.com
|
||||||
Romain Vimont
|
Romain Vimont
|
||||||
.ME
|
.ME
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ bool
|
|||||||
sc_aoa_start(struct sc_aoa *aoa) {
|
sc_aoa_start(struct sc_aoa *aoa) {
|
||||||
LOGD("Starting AOA thread");
|
LOGD("Starting AOA thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&aoa->thread, run_aoa_thread, "aoa_thread", aoa);
|
bool ok = sc_thread_create(&aoa->thread, run_aoa_thread, "scrcpy-aoa", aoa);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start AOA thread");
|
LOGC("Could not start AOA thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ struct sc_shortcut {
|
|||||||
const char *text;
|
const char *text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sc_envvar {
|
||||||
|
const char *name;
|
||||||
|
const char *text;
|
||||||
|
};
|
||||||
|
|
||||||
struct sc_getopt_adapter {
|
struct sc_getopt_adapter {
|
||||||
char *optstring;
|
char *optstring;
|
||||||
struct option *longopts;
|
struct option *longopts;
|
||||||
@@ -585,6 +590,21 @@ static const struct sc_shortcut shortcuts[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct sc_envvar envvars[] = {
|
||||||
|
{
|
||||||
|
.name = "ADB",
|
||||||
|
.text = "Path to adb executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "SCRCPY_ICON_PATH",
|
||||||
|
.text = "Path to the program icon",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "SCRCPY_SERVER_PATH",
|
||||||
|
.text = "Path to the server binary",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
sc_getopt_adapter_create_optstring(void) {
|
sc_getopt_adapter_create_optstring(void) {
|
||||||
struct sc_strbuf buf;
|
struct sc_strbuf buf;
|
||||||
@@ -678,7 +698,7 @@ sc_getopt_adapter_init(struct sc_getopt_adapter *adapter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sc_getopt_adapter_destroy(struct sc_getopt_adapter *adapter) {
|
sc_getopt_adapter_destroy(struct sc_getopt_adapter *adapter) {
|
||||||
@@ -776,7 +796,7 @@ print_shortcuts_intro(unsigned cols) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s\n", intro);
|
printf("\n%s\n", intro);
|
||||||
free(intro);
|
free(intro);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,6 +824,23 @@ print_shortcut(const struct sc_shortcut *shortcut, unsigned cols) {
|
|||||||
free(text);
|
free(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_envvar(const struct sc_envvar *envvar, unsigned cols) {
|
||||||
|
assert(cols > 8); // sc_str_wrap_lines() requires indent < columns
|
||||||
|
assert(envvar->name);
|
||||||
|
assert(envvar->text);
|
||||||
|
|
||||||
|
printf("\n %s\n", envvar->name);
|
||||||
|
char *text = sc_str_wrap_lines(envvar->text, cols, 8);
|
||||||
|
if (!text) {
|
||||||
|
printf("<ERROR>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s\n", text);
|
||||||
|
free(text);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scrcpy_print_usage(const char *arg0) {
|
scrcpy_print_usage(const char *arg0) {
|
||||||
#define SC_TERM_COLS_DEFAULT 80
|
#define SC_TERM_COLS_DEFAULT 80
|
||||||
@@ -831,11 +868,17 @@ scrcpy_print_usage(const char *arg0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print shortcuts section
|
// Print shortcuts section
|
||||||
printf("\nShortcuts:\n\n");
|
printf("\nShortcuts:\n");
|
||||||
print_shortcuts_intro(cols);
|
print_shortcuts_intro(cols);
|
||||||
for (size_t i = 0; i < ARRAY_LEN(shortcuts); ++i) {
|
for (size_t i = 0; i < ARRAY_LEN(shortcuts); ++i) {
|
||||||
print_shortcut(&shortcuts[i], cols);
|
print_shortcut(&shortcuts[i], cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print environment variables section
|
||||||
|
printf("\nEnvironment variables:\n");
|
||||||
|
for (size_t i = 0; i < ARRAY_LEN(envvars); ++i) {
|
||||||
|
print_envvar(&envvars[i], cols);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|||||||
@@ -35,15 +35,6 @@
|
|||||||
# define SCRCPY_LAVF_HAS_AVFORMATCONTEXT_URL
|
# define SCRCPY_LAVF_HAS_AVFORMATCONTEXT_URL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
|
||||||
// <https://wiki.libsdl.org/SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH>
|
|
||||||
# define SCRCPY_SDL_HAS_HINT_MOUSE_FOCUS_CLICKTHROUGH
|
|
||||||
// <https://wiki.libsdl.org/SDL_GetDisplayUsableBounds>
|
|
||||||
# define SCRCPY_SDL_HAS_GET_DISPLAY_USABLE_BOUNDS
|
|
||||||
// <https://wiki.libsdl.org/SDL_WindowFlags>
|
|
||||||
# define SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||||
// <https://github.com/libsdl-org/SDL/commit/d7a318de563125e5bb465b1000d6bc9576fbc6fc>
|
// <https://github.com/libsdl-org/SDL/commit/d7a318de563125e5bb465b1000d6bc9576fbc6fc>
|
||||||
# define SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
# define SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ static const char *const android_motionevent_action_labels[] = {
|
|||||||
"pointer-up",
|
"pointer-up",
|
||||||
"hover-move",
|
"hover-move",
|
||||||
"scroll",
|
"scroll",
|
||||||
"hover-enter"
|
"hover-enter",
|
||||||
"hover-exit",
|
"hover-exit",
|
||||||
"btn-press",
|
"btn-press",
|
||||||
"btn-release",
|
"btn-release",
|
||||||
@@ -69,7 +69,7 @@ write_position(uint8_t *buf, const struct sc_position *position) {
|
|||||||
buffer_write16be(&buf[10], position->screen_size.height);
|
buffer_write16be(&buf[10], position->screen_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write length (2 bytes) + string (non nul-terminated)
|
// write length (4 bytes) + string (non null-terminated)
|
||||||
static size_t
|
static size_t
|
||||||
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
|
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
|
||||||
size_t len = sc_str_utf8_truncation_index(utf8, max_len);
|
size_t len = sc_str_utf8_truncation_index(utf8, max_len);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#define CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
|
#define CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
|
||||||
|
|
||||||
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
|
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
|
||||||
// type: 1 byte; paste flag: 1 byte; length: 4 bytes
|
// type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes
|
||||||
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 6)
|
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 14)
|
||||||
|
|
||||||
#define POINTER_ID_MOUSE UINT64_C(-1)
|
#define POINTER_ID_MOUSE UINT64_C(-1)
|
||||||
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
#define POINTER_ID_VIRTUAL_FINGER UINT64_C(-2)
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ controller_start(struct controller *controller) {
|
|||||||
LOGD("Starting controller thread");
|
LOGD("Starting controller thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&controller->thread, run_controller,
|
bool ok = sc_thread_create(&controller->thread, run_controller,
|
||||||
"controller", controller);
|
"scrcpy-ctl", controller);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start controller thread");
|
LOGC("Could not start controller thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decoder->codec_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
|
||||||
|
|
||||||
if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) {
|
if (avcodec_open2(decoder->codec_ctx, codec, NULL) < 0) {
|
||||||
LOGE("Could not open codec");
|
LOGE("Could not open codec");
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
avcodec_free_context(&decoder->codec_ctx);
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ file_handler_start(struct file_handler *file_handler) {
|
|||||||
LOGD("Starting file_handler thread");
|
LOGD("Starting file_handler thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&file_handler->thread, run_file_handler,
|
bool ok = sc_thread_create(&file_handler->thread, run_file_handler,
|
||||||
"file_handler", file_handler);
|
"scrcpy-file", file_handler);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start file_handler thread");
|
LOGC("Could not start file_handler thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ fps_counter_start(struct fps_counter *counter) {
|
|||||||
// same thread, no need to lock
|
// same thread, no need to lock
|
||||||
if (!counter->thread_started) {
|
if (!counter->thread_started) {
|
||||||
bool ok = sc_thread_create(&counter->thread, run_fps_counter,
|
bool ok = sc_thread_create(&counter->thread, run_fps_counter,
|
||||||
"fps counter", counter);
|
"scrcpy-fps", counter);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Could not start FPS counter thread");
|
LOGE("Could not start FPS counter thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ bool
|
|||||||
receiver_start(struct receiver *receiver) {
|
receiver_start(struct receiver *receiver) {
|
||||||
LOGD("Starting receiver thread");
|
LOGD("Starting receiver thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&receiver->thread, run_receiver, "receiver",
|
bool ok = sc_thread_create(&receiver->thread, run_receiver,
|
||||||
receiver);
|
"scrcpy-receiver", receiver);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start receiver thread");
|
LOGC("Could not start receiver thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ recorder_open(struct recorder *recorder, const AVCodec *input_codec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOGD("Starting recorder thread");
|
LOGD("Starting recorder thread");
|
||||||
ok = sc_thread_create(&recorder->thread, run_recorder, "recorder",
|
ok = sc_thread_create(&recorder->thread, run_recorder, "scrcpy-recorder",
|
||||||
recorder);
|
recorder);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start recorder thread");
|
LOGC("Could not start recorder thread");
|
||||||
|
|||||||
@@ -94,12 +94,10 @@ sdl_set_hints(const char *render_driver) {
|
|||||||
LOGW("Could not enable linear filtering");
|
LOGW("Could not enable linear filtering");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCRCPY_SDL_HAS_HINT_MOUSE_FOCUS_CLICKTHROUGH
|
|
||||||
// Handle a click to gain focus as any other click
|
// Handle a click to gain focus as any other click
|
||||||
if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) {
|
if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) {
|
||||||
LOGW("Could not enable mouse focus clickthrough");
|
LOGW("Could not enable mouse focus clickthrough");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
#ifdef SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS
|
||||||
// Disable synthetic mouse events from touch events
|
// Disable synthetic mouse events from touch events
|
||||||
|
|||||||
@@ -64,12 +64,7 @@ set_window_size(struct screen *screen, struct sc_size new_size) {
|
|||||||
static bool
|
static bool
|
||||||
get_preferred_display_bounds(struct sc_size *bounds) {
|
get_preferred_display_bounds(struct sc_size *bounds) {
|
||||||
SDL_Rect rect;
|
SDL_Rect rect;
|
||||||
#ifdef SCRCPY_SDL_HAS_GET_DISPLAY_USABLE_BOUNDS
|
if (SDL_GetDisplayUsableBounds(0, &rect)) {
|
||||||
# define GET_DISPLAY_BOUNDS(i, r) SDL_GetDisplayUsableBounds((i), (r))
|
|
||||||
#else
|
|
||||||
# define GET_DISPLAY_BOUNDS(i, r) SDL_GetDisplayBounds((i), (r))
|
|
||||||
#endif
|
|
||||||
if (GET_DISPLAY_BOUNDS(0, &rect)) {
|
|
||||||
LOGW("Could not get display usable bounds: %s", SDL_GetError());
|
LOGW("Could not get display usable bounds: %s", SDL_GetError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -394,12 +389,7 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
|||||||
| SDL_WINDOW_RESIZABLE
|
| SDL_WINDOW_RESIZABLE
|
||||||
| SDL_WINDOW_ALLOW_HIGHDPI;
|
| SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
if (params->always_on_top) {
|
if (params->always_on_top) {
|
||||||
#ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP
|
|
||||||
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
||||||
#else
|
|
||||||
LOGW("The 'always on top' flag is not available "
|
|
||||||
"(compile with SDL >= 2.0.5 to enable it)");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (params->window_borderless) {
|
if (params->window_borderless) {
|
||||||
window_flags |= SDL_WINDOW_BORDERLESS;
|
window_flags |= SDL_WINDOW_BORDERLESS;
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ execute_server(struct sc_server *server,
|
|||||||
ADD_PARAM("power_off_on_close=%s", STRBOOL(params->power_off_on_close));
|
ADD_PARAM("power_off_on_close=%s", STRBOOL(params->power_off_on_close));
|
||||||
}
|
}
|
||||||
if (!params->clipboard_autosync) {
|
if (!params->clipboard_autosync) {
|
||||||
// By defaut, clipboard_autosync is true
|
// By default, clipboard_autosync is true
|
||||||
ADD_PARAM("clipboard_autosync=%s", STRBOOL(params->clipboard_autosync));
|
ADD_PARAM("clipboard_autosync=%s", STRBOOL(params->clipboard_autosync));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +388,7 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
|||||||
assert(tunnel->enabled);
|
assert(tunnel->enabled);
|
||||||
|
|
||||||
const char *serial = server->params.serial;
|
const char *serial = server->params.serial;
|
||||||
|
bool control = server->params.control;
|
||||||
|
|
||||||
sc_socket video_socket = SC_SOCKET_NONE;
|
sc_socket video_socket = SC_SOCKET_NONE;
|
||||||
sc_socket control_socket = SC_SOCKET_NONE;
|
sc_socket control_socket = SC_SOCKET_NONE;
|
||||||
@@ -397,10 +398,13 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
control_socket = net_accept_intr(&server->intr, tunnel->server_socket);
|
if (control) {
|
||||||
|
control_socket =
|
||||||
|
net_accept_intr(&server->intr, tunnel->server_socket);
|
||||||
if (control_socket == SC_SOCKET_NONE) {
|
if (control_socket == SC_SOCKET_NONE) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t tunnel_host = server->params.tunnel_host;
|
uint32_t tunnel_host = server->params.tunnel_host;
|
||||||
if (!tunnel_host) {
|
if (!tunnel_host) {
|
||||||
@@ -420,17 +424,20 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we know that the device is listening, we don't need several attempts
|
if (control) {
|
||||||
|
// we know that the device is listening, we don't need several
|
||||||
|
// attempts
|
||||||
control_socket = net_socket();
|
control_socket = net_socket();
|
||||||
if (control_socket == SC_SOCKET_NONE) {
|
if (control_socket == SC_SOCKET_NONE) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
bool ok = net_connect_intr(&server->intr, control_socket, tunnel_host,
|
bool ok = net_connect_intr(&server->intr, control_socket,
|
||||||
tunnel_port);
|
tunnel_host, tunnel_port);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we don't need the adb tunnel anymore
|
// we don't need the adb tunnel anymore
|
||||||
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
||||||
@@ -442,7 +449,7 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(video_socket != SC_SOCKET_NONE);
|
assert(video_socket != SC_SOCKET_NONE);
|
||||||
assert(control_socket != SC_SOCKET_NONE);
|
assert(!control || control_socket != SC_SOCKET_NONE);
|
||||||
|
|
||||||
server->video_socket = video_socket;
|
server->video_socket = video_socket;
|
||||||
server->control_socket = control_socket;
|
server->control_socket = control_socket;
|
||||||
@@ -756,6 +763,17 @@ run_server(void *data) {
|
|||||||
}
|
}
|
||||||
sc_mutex_unlock(&server->mutex);
|
sc_mutex_unlock(&server->mutex);
|
||||||
|
|
||||||
|
// Interrupt sockets to wake up socket blocking calls on the server
|
||||||
|
assert(server->video_socket != SC_SOCKET_NONE);
|
||||||
|
net_interrupt(server->video_socket);
|
||||||
|
net_close(server->video_socket);
|
||||||
|
|
||||||
|
if (server->control_socket != SC_SOCKET_NONE) {
|
||||||
|
// There is no control_socket if --no-control is set
|
||||||
|
net_interrupt(server->control_socket);
|
||||||
|
net_close(server->control_socket);
|
||||||
|
}
|
||||||
|
|
||||||
// Give some delay for the server to terminate properly
|
// Give some delay for the server to terminate properly
|
||||||
#define WATCHDOG_DELAY SC_TICK_FROM_SEC(1)
|
#define WATCHDOG_DELAY SC_TICK_FROM_SEC(1)
|
||||||
sc_tick deadline = sc_tick_now() + WATCHDOG_DELAY;
|
sc_tick deadline = sc_tick_now() + WATCHDOG_DELAY;
|
||||||
@@ -786,7 +804,8 @@ error_connection_failed:
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
sc_server_start(struct sc_server *server) {
|
sc_server_start(struct sc_server *server) {
|
||||||
bool ok = sc_thread_create(&server->thread, run_server, "server", server);
|
bool ok =
|
||||||
|
sc_thread_create(&server->thread, run_server, "scrcpy-server", server);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Could not create server thread");
|
LOGE("Could not create server thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -284,7 +284,8 @@ bool
|
|||||||
stream_start(struct stream *stream) {
|
stream_start(struct stream *stream) {
|
||||||
LOGD("Starting stream thread");
|
LOGD("Starting stream thread");
|
||||||
|
|
||||||
bool ok = sc_thread_create(&stream->thread, run_stream, "stream", stream);
|
bool ok =
|
||||||
|
sc_thread_create(&stream->thread, run_stream, "scrcpy-stream", stream);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start stream thread");
|
LOGC("Could not start stream thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -119,6 +119,13 @@ sc_process_execute_p(const char *const argv[], sc_pid *pid, unsigned flags,
|
|||||||
|
|
||||||
close(internal[0]);
|
close(internal[0]);
|
||||||
enum sc_process_result err;
|
enum sc_process_result err;
|
||||||
|
|
||||||
|
// Somehow SDL masks many signals - undo them for other processes
|
||||||
|
// https://github.com/libsdl-org/SDL/blob/release-2.0.18/src/thread/pthread/SDL_systhread.c#L167
|
||||||
|
sigset_t mask;
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||||
|
|
||||||
if (fcntl(internal[1], F_SETFD, FD_CLOEXEC) == 0) {
|
if (fcntl(internal[1], F_SETFD, FD_CLOEXEC) == 0) {
|
||||||
execvp(argv[0], (char *const *) argv);
|
execvp(argv[0], (char *const *) argv);
|
||||||
perror("exec");
|
perror("exec");
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ sc_process_observer_init(struct sc_process_observer *observer, sc_pid pid,
|
|||||||
observer->listener_userdata = listener_userdata;
|
observer->listener_userdata = listener_userdata;
|
||||||
observer->terminated = false;
|
observer->terminated = false;
|
||||||
|
|
||||||
ok = sc_thread_create(&observer->thread, run_observer, "process_observer",
|
ok = sc_thread_create(&observer->thread, run_observer, "scrcpy-proc",
|
||||||
observer);
|
observer);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
sc_cond_destroy(&observer->cond_terminated);
|
sc_cond_destroy(&observer->cond_terminated);
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ sc_str_wrap_lines(const char *input, unsigned columns, unsigned indent) {
|
|||||||
|
|
||||||
APPEND_INDENT();
|
APPEND_INDENT();
|
||||||
|
|
||||||
// The last separator encountered, it must be inserted only conditionnaly,
|
// The last separator encountered, it must be inserted only conditionally,
|
||||||
// depending on the next token
|
// depending on the next token
|
||||||
char pending = 0;
|
char pending = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
bool
|
bool
|
||||||
sc_thread_create(sc_thread *thread, sc_thread_fn fn, const char *name,
|
sc_thread_create(sc_thread *thread, sc_thread_fn fn, const char *name,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
// The thread name length is limited on some systems. Never use a name
|
||||||
|
// longer than 16 bytes (including the final '\0')
|
||||||
|
assert(strlen(name) <= 15);
|
||||||
|
|
||||||
SDL_Thread *sdl_thread = SDL_CreateThread(fn, name, userdata);
|
SDL_Thread *sdl_thread = SDL_CreateThread(fn, name, userdata);
|
||||||
if (!sdl_thread) {
|
if (!sdl_thread) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
|
|||||||
@@ -1,16 +1,55 @@
|
|||||||
#include "tick.h"
|
#include "tick.h"
|
||||||
|
|
||||||
#include <SDL2/SDL_timer.h>
|
#include <assert.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
sc_tick
|
sc_tick
|
||||||
sc_tick_now(void) {
|
sc_tick_now(void) {
|
||||||
// SDL_GetTicks() resolution is in milliseconds, but sc_tick are expressed
|
#ifndef _WIN32
|
||||||
// in microseconds to store PTS without precision loss.
|
// Maximum sc_tick precision (microsecond)
|
||||||
//
|
struct timespec ts;
|
||||||
// As an alternative, SDL_GetPerformanceCounter() and
|
int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
// SDL_GetPerformanceFrequency() could be used, but:
|
if (ret) {
|
||||||
// - the conversions (avoiding overflow) are expansive, since the
|
abort();
|
||||||
// frequency is not known at compile time;
|
}
|
||||||
// - in practice, we don't need more precision for now.
|
|
||||||
return (sc_tick) SDL_GetTicks() * 1000;
|
return SC_TICK_FROM_SEC(ts.tv_sec) + SC_TICK_FROM_NS(ts.tv_nsec);
|
||||||
|
#else
|
||||||
|
LARGE_INTEGER c;
|
||||||
|
|
||||||
|
// On systems that run Windows XP or later, the function will always
|
||||||
|
// succeed and will thus never return zero.
|
||||||
|
// <https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter>
|
||||||
|
// <https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency>
|
||||||
|
|
||||||
|
BOOL ok = QueryPerformanceCounter(&c);
|
||||||
|
assert(ok);
|
||||||
|
(void) ok;
|
||||||
|
|
||||||
|
LONGLONG counter = c.QuadPart;
|
||||||
|
|
||||||
|
static LONGLONG frequency;
|
||||||
|
if (!frequency) {
|
||||||
|
// Initialize on first call
|
||||||
|
LARGE_INTEGER f;
|
||||||
|
ok = QueryPerformanceFrequency(&f);
|
||||||
|
assert(ok);
|
||||||
|
frequency = f.QuadPart;
|
||||||
|
assert(frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frequency % SC_TICK_FREQ == 0) {
|
||||||
|
// Expected case (typically frequency = 10000000, i.e. 100ns precision)
|
||||||
|
sc_tick div = frequency / SC_TICK_FREQ;
|
||||||
|
return SC_TICK_FROM_US(counter / div);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the division to avoid overflow
|
||||||
|
sc_tick secs = SC_TICK_FROM_SEC(counter / frequency);
|
||||||
|
sc_tick subsec = SC_TICK_FREQ * (counter % frequency) / frequency;
|
||||||
|
return secs + subsec;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ typedef int64_t sc_tick;
|
|||||||
#define SC_TICK_FREQ 1000000 // microsecond
|
#define SC_TICK_FREQ 1000000 // microsecond
|
||||||
|
|
||||||
// To be adapted if SC_TICK_FREQ changes
|
// To be adapted if SC_TICK_FREQ changes
|
||||||
|
#define SC_TICK_TO_NS(tick) ((tick) * 1000)
|
||||||
#define SC_TICK_TO_US(tick) (tick)
|
#define SC_TICK_TO_US(tick) (tick)
|
||||||
#define SC_TICK_TO_MS(tick) ((tick) / 1000)
|
#define SC_TICK_TO_MS(tick) ((tick) / 1000)
|
||||||
#define SC_TICK_TO_SEC(tick) ((tick) / 1000000)
|
#define SC_TICK_TO_SEC(tick) ((tick) / 1000000)
|
||||||
|
#define SC_TICK_FROM_NS(ns) ((ns) / 1000)
|
||||||
#define SC_TICK_FROM_US(us) (us)
|
#define SC_TICK_FROM_US(us) (us)
|
||||||
#define SC_TICK_FROM_MS(ms) ((ms) * 1000)
|
#define SC_TICK_FROM_MS(ms) ((ms) * 1000)
|
||||||
#define SC_TICK_FROM_SEC(sec) ((sec) * 1000000)
|
#define SC_TICK_FROM_SEC(sec) ((sec) * 1000000)
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ sc_v4l2_sink_open(struct sc_v4l2_sink *vs) {
|
|||||||
vs->stopped = false;
|
vs->stopped = false;
|
||||||
|
|
||||||
LOGD("Starting v4l2 thread");
|
LOGD("Starting v4l2 thread");
|
||||||
ok = sc_thread_create(&vs->thread, run_v4l2_sink, "v4l2", vs);
|
ok = sc_thread_create(&vs->thread, run_v4l2_sink, "scrcpy-v4l2", vs);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGC("Could not start v4l2 thread");
|
LOGC("Could not start v4l2 thread");
|
||||||
goto error_av_packet_free;
|
goto error_av_packet_free;
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ bool
|
|||||||
sc_video_buffer_start(struct sc_video_buffer *vb) {
|
sc_video_buffer_start(struct sc_video_buffer *vb) {
|
||||||
if (vb->buffering_time) {
|
if (vb->buffering_time) {
|
||||||
bool ok =
|
bool ok =
|
||||||
sc_thread_create(&vb->b.thread, run_buffering, "buffering", vb);
|
sc_thread_create(&vb->b.thread, run_buffering, "scrcpy-vbuf", vb);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Could not start buffering thread");
|
LOGE("Could not start buffering thread");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -169,4 +169,4 @@ int main(int argc, char *argv[]) {
|
|||||||
test_options2();
|
test_options2();
|
||||||
test_parse_shortcut_mods();
|
test_parse_shortcut_mods();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ static void test_serialize_inject_text_long(void) {
|
|||||||
struct control_msg msg;
|
struct control_msg msg;
|
||||||
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
msg.type = CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||||
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
char text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH + 1];
|
||||||
memset(text, 'a', sizeof(text));
|
memset(text, 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||||
text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
|
text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
|
||||||
msg.inject_text.text = text;
|
msg.inject_text.text = text;
|
||||||
|
|
||||||
@@ -250,6 +250,40 @@ static void test_serialize_set_clipboard(void) {
|
|||||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_serialize_set_clipboard_long(void) {
|
||||||
|
struct control_msg msg = {
|
||||||
|
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
|
.set_clipboard = {
|
||||||
|
.sequence = UINT64_C(0x0102030405060708),
|
||||||
|
.paste = true,
|
||||||
|
.text = NULL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
char text[CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH + 1];
|
||||||
|
memset(text, 'a', CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
||||||
|
text[CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH] = '\0';
|
||||||
|
msg.set_clipboard.text = text;
|
||||||
|
|
||||||
|
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||||
|
size_t size = control_msg_serialize(&msg, buf);
|
||||||
|
assert(size == CONTROL_MSG_MAX_SIZE);
|
||||||
|
|
||||||
|
unsigned char expected[CONTROL_MSG_MAX_SIZE] = {
|
||||||
|
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||||
|
1, // paste
|
||||||
|
// text length
|
||||||
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 24,
|
||||||
|
(CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 16) & 0xff,
|
||||||
|
(CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH >> 8) & 0xff,
|
||||||
|
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH & 0xff,
|
||||||
|
};
|
||||||
|
memset(expected + 14, 'a', CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH);
|
||||||
|
|
||||||
|
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
static void test_serialize_set_screen_power_mode(void) {
|
static void test_serialize_set_screen_power_mode(void) {
|
||||||
struct control_msg msg = {
|
struct control_msg msg = {
|
||||||
.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||||
@@ -299,6 +333,7 @@ int main(int argc, char *argv[]) {
|
|||||||
test_serialize_collapse_panels();
|
test_serialize_collapse_panels();
|
||||||
test_serialize_get_clipboard();
|
test_serialize_get_clipboard();
|
||||||
test_serialize_set_clipboard();
|
test_serialize_set_clipboard();
|
||||||
|
test_serialize_set_clipboard_long();
|
||||||
test_serialize_set_screen_power_mode();
|
test_serialize_set_screen_power_mode();
|
||||||
test_serialize_rotate_device();
|
test_serialize_rotate_device();
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
34
bump_version
Executable file
34
bump_version
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# This script bump scrcpy version by editing all the necessary files.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# ./bump_version 1.23.4
|
||||||
|
#
|
||||||
|
# Then check the diff manually to confirm that everything is ok.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# != 1 ]]
|
||||||
|
then
|
||||||
|
echo "Syntax: $0 <version>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION="$1"
|
||||||
|
|
||||||
|
a=( ${VERSION//./ } )
|
||||||
|
MAJOR="${a[0]:-0}"
|
||||||
|
MINOR="${a[1]:-0}"
|
||||||
|
PATCH="${a[2]:-0}"
|
||||||
|
|
||||||
|
# If VERSION is 1.23.4, then VERSION_CODE is 12304
|
||||||
|
VERSION_CODE="$(( $MAJOR * 10000 + $MINOR * 100 + "$PATCH" ))"
|
||||||
|
|
||||||
|
echo "$VERSION: major=$MAJOR minor=$MINOR patch=$PATCH [versionCode=$VERSION_CODE]"
|
||||||
|
sed -i "s/^\(\s*version: \)'[^']*'/\1'$VERSION'/" meson.build
|
||||||
|
sed -i "s/^\(\s*versionCode \).*/\1$VERSION_CODE/;s/^\(\s*versionName \).*/\1\"$VERSION\"/" server/build.gradle
|
||||||
|
sed -i "s/^\(SCRCPY_VERSION_NAME=\).*/\1$VERSION/" server/build_without_gradle.sh
|
||||||
|
sed -i "s/^\(\s*VALUE \"ProductVersion\", \)\"[^\"]*\"/\1\"$VERSION\"/" app/scrcpy-windows.rc
|
||||||
|
echo done
|
||||||
@@ -7,6 +7,7 @@ cpp = 'i686-w64-mingw32-g++'
|
|||||||
ar = 'i686-w64-mingw32-ar'
|
ar = 'i686-w64-mingw32-ar'
|
||||||
strip = 'i686-w64-mingw32-strip'
|
strip = 'i686-w64-mingw32-strip'
|
||||||
pkgconfig = 'i686-w64-mingw32-pkg-config'
|
pkgconfig = 'i686-w64-mingw32-pkg-config'
|
||||||
|
windres = 'i686-w64-mingw32-windres'
|
||||||
|
|
||||||
[host_machine]
|
[host_machine]
|
||||||
system = 'windows'
|
system = 'windows'
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ cpp = 'x86_64-w64-mingw32-g++'
|
|||||||
ar = 'x86_64-w64-mingw32-ar'
|
ar = 'x86_64-w64-mingw32-ar'
|
||||||
strip = 'x86_64-w64-mingw32-strip'
|
strip = 'x86_64-w64-mingw32-strip'
|
||||||
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
|
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
|
||||||
|
windres = 'x86_64-w64-mingw32-windres'
|
||||||
|
|
||||||
[host_machine]
|
[host_machine]
|
||||||
system = 'windows'
|
system = 'windows'
|
||||||
|
|||||||
BIN
data/icon.ico
Normal file
BIN
data/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -1,6 +1,5 @@
|
|||||||
option('compile_app', type: 'boolean', value: true, description: 'Build the client')
|
option('compile_app', type: 'boolean', value: true, description: 'Build the client')
|
||||||
option('compile_server', type: 'boolean', value: true, description: 'Build the server')
|
option('compile_server', type: 'boolean', value: true, description: 'Build the server')
|
||||||
option('crossbuild_windows', type: 'boolean', value: false, description: 'Build for Windows from Linux')
|
|
||||||
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
|
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
|
||||||
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
|
||||||
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
|
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ build-win32: prepare-deps-win32
|
|||||||
meson "$(WIN32_BUILD_DIR)" \
|
meson "$(WIN32_BUILD_DIR)" \
|
||||||
--cross-file cross_win32.txt \
|
--cross-file cross_win32.txt \
|
||||||
--buildtype release --strip -Db_lto=true \
|
--buildtype release --strip -Db_lto=true \
|
||||||
-Dcrossbuild_windows=true \
|
|
||||||
-Dcompile_server=false \
|
-Dcompile_server=false \
|
||||||
-Dportable=true )
|
-Dportable=true )
|
||||||
ninja -C "$(WIN32_BUILD_DIR)"
|
ninja -C "$(WIN32_BUILD_DIR)"
|
||||||
@@ -83,7 +82,6 @@ build-win64: prepare-deps-win64
|
|||||||
meson "$(WIN64_BUILD_DIR)" \
|
meson "$(WIN64_BUILD_DIR)" \
|
||||||
--cross-file cross_win64.txt \
|
--cross-file cross_win64.txt \
|
||||||
--buildtype release --strip -Db_lto=true \
|
--buildtype release --strip -Db_lto=true \
|
||||||
-Dcrossbuild_windows=true \
|
|
||||||
-Dcompile_server=false \
|
-Dcompile_server=false \
|
||||||
-Dportable=true )
|
-Dportable=true )
|
||||||
ninja -C "$(WIN64_BUILD_DIR)"
|
ninja -C "$(WIN64_BUILD_DIR)"
|
||||||
|
|||||||
@@ -30,8 +30,13 @@ public final class DesktopConnection implements Closeable {
|
|||||||
private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException {
|
private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException {
|
||||||
this.videoSocket = videoSocket;
|
this.videoSocket = videoSocket;
|
||||||
this.controlSocket = controlSocket;
|
this.controlSocket = controlSocket;
|
||||||
|
if (controlSocket != null) {
|
||||||
controlInputStream = controlSocket.getInputStream();
|
controlInputStream = controlSocket.getInputStream();
|
||||||
controlOutputStream = controlSocket.getOutputStream();
|
controlOutputStream = controlSocket.getOutputStream();
|
||||||
|
} else {
|
||||||
|
controlInputStream = null;
|
||||||
|
controlOutputStream = null;
|
||||||
|
}
|
||||||
videoFd = videoSocket.getFileDescriptor();
|
videoFd = videoSocket.getFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,26 +46,29 @@ public final class DesktopConnection implements Closeable {
|
|||||||
return localSocket;
|
return localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
|
public static DesktopConnection open(Device device, boolean tunnelForward, boolean control) throws IOException {
|
||||||
LocalSocket videoSocket;
|
LocalSocket videoSocket;
|
||||||
LocalSocket controlSocket;
|
LocalSocket controlSocket = null;
|
||||||
if (tunnelForward) {
|
if (tunnelForward) {
|
||||||
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
|
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
|
||||||
try {
|
try {
|
||||||
videoSocket = localServerSocket.accept();
|
videoSocket = localServerSocket.accept();
|
||||||
// send one byte so the client may read() to detect a connection error
|
// send one byte so the client may read() to detect a connection error
|
||||||
videoSocket.getOutputStream().write(0);
|
videoSocket.getOutputStream().write(0);
|
||||||
|
if (control) {
|
||||||
try {
|
try {
|
||||||
controlSocket = localServerSocket.accept();
|
controlSocket = localServerSocket.accept();
|
||||||
} catch (IOException | RuntimeException e) {
|
} catch (IOException | RuntimeException e) {
|
||||||
videoSocket.close();
|
videoSocket.close();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
localServerSocket.close();
|
localServerSocket.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
videoSocket = connect(SOCKET_NAME);
|
videoSocket = connect(SOCKET_NAME);
|
||||||
|
if (control) {
|
||||||
try {
|
try {
|
||||||
controlSocket = connect(SOCKET_NAME);
|
controlSocket = connect(SOCKET_NAME);
|
||||||
} catch (IOException | RuntimeException e) {
|
} catch (IOException | RuntimeException e) {
|
||||||
@@ -68,6 +76,7 @@ public final class DesktopConnection implements Closeable {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DesktopConnection connection = new DesktopConnection(videoSocket, controlSocket);
|
DesktopConnection connection = new DesktopConnection(videoSocket, controlSocket);
|
||||||
Size videoSize = device.getScreenInfo().getVideoSize();
|
Size videoSize = device.getScreenInfo().getVideoSize();
|
||||||
@@ -79,10 +88,12 @@ public final class DesktopConnection implements Closeable {
|
|||||||
videoSocket.shutdownInput();
|
videoSocket.shutdownInput();
|
||||||
videoSocket.shutdownOutput();
|
videoSocket.shutdownOutput();
|
||||||
videoSocket.close();
|
videoSocket.close();
|
||||||
|
if (controlSocket != null) {
|
||||||
controlSocket.shutdownInput();
|
controlSocket.shutdownInput();
|
||||||
controlSocket.shutdownOutput();
|
controlSocket.shutdownOutput();
|
||||||
controlSocket.close();
|
controlSocket.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void send(String deviceName, int width, int height) throws IOException {
|
private void send(String deviceName, int width, int height) throws IOException {
|
||||||
byte[] buffer = new byte[DEVICE_NAME_FIELD_LENGTH + 4];
|
byte[] buffer = new byte[DEVICE_NAME_FIELD_LENGTH + 4];
|
||||||
|
|||||||
@@ -66,14 +66,15 @@ public final class Server {
|
|||||||
Thread initThread = startInitThread(options);
|
Thread initThread = startInitThread(options);
|
||||||
|
|
||||||
boolean tunnelForward = options.isTunnelForward();
|
boolean tunnelForward = options.isTunnelForward();
|
||||||
|
boolean control = options.getControl();
|
||||||
|
|
||||||
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
|
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward, control)) {
|
||||||
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate(), options.getMaxFps(), codecOptions,
|
||||||
options.getEncoderName());
|
options.getEncoderName());
|
||||||
|
|
||||||
Thread controllerThread = null;
|
Thread controllerThread = null;
|
||||||
Thread deviceMessageSenderThread = null;
|
Thread deviceMessageSenderThread = null;
|
||||||
if (options.getControl()) {
|
if (control) {
|
||||||
final Controller controller = new Controller(device, connection, options.getClipboardAutosync());
|
final Controller controller = new Controller(device, connection, options.getClipboardAutosync());
|
||||||
|
|
||||||
// asynchronous
|
// asynchronous
|
||||||
|
|||||||
Reference in New Issue
Block a user