Compare commits
10 Commits
install
...
tcpip_anyp
Author | SHA1 | Date | |
---|---|---|---|
bd1deffa70 | |||
6469b55861 | |||
597703b62e | |||
48bb6f2ea8 | |||
d71587e39b | |||
b62424a98a | |||
ffc7b91693 | |||
cb46e4a64a | |||
16e2c1ce26 | |||
1bfbadef96 |
@ -395,8 +395,8 @@ address), connect the device over USB, then run:
|
||||
scrcpy --tcpip # without arguments
|
||||
```
|
||||
|
||||
It will automatically find the device IP address, enable TCP/IP mode, then
|
||||
connect to the device before starting.
|
||||
It will automatically find the device IP address and adb port, enable TCP/IP
|
||||
mode if necessary, then connect to the device before starting.
|
||||
|
||||
##### Manual
|
||||
|
||||
|
@ -93,6 +93,11 @@ _scrcpy() {
|
||||
COMPREPLY=($(compgen -W 'verbose debug info warn error' -- "$cur"))
|
||||
return
|
||||
;;
|
||||
-s|--serial)
|
||||
# Use 'adb devices' to list serial numbers
|
||||
COMPREPLY=($(compgen -W "$("${ADB:-adb}" devices | awk '$2 == "device" {print $1}')" -- ${cur}))
|
||||
return
|
||||
;;
|
||||
-b|--bitrate \
|
||||
|--codec-options \
|
||||
|--crop \
|
||||
@ -103,7 +108,6 @@ _scrcpy() {
|
||||
|-m|--max-size \
|
||||
|-p|--port \
|
||||
|--push-target \
|
||||
|-s|--serial \
|
||||
|--tunnel-host \
|
||||
|--tunnel-port \
|
||||
|--v4l2-buffer \
|
||||
|
@ -47,7 +47,7 @@ arguments=(
|
||||
'--record-format=[Force recording format]:format:(mp4 mkv)'
|
||||
'--render-driver=[Request SDL to use the given render driver]:driver name:(direct3d opengl opengles2 opengles metal software)'
|
||||
'--rotation=[Set the initial display rotation]:rotation values:(0 1 2 3)'
|
||||
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]'
|
||||
{-s,--serial=}'[The device serial number \(mandatory for multiple devices only\)]:serial:($("${ADB-adb}" devices | awk '\''$2 == "device" {print $1}'\''))'
|
||||
'--shortcut-mod=[\[key1,key2+key3,...\] Specify the modifiers to use for scrcpy shortcuts]:shortcut mod:(lctrl rctrl lalt ralt lsuper rsuper)'
|
||||
{-S,--turn-screen-off}'[Turn the device screen off immediately]'
|
||||
{-t,--show-touches}'[Show physical touches]'
|
||||
|
@ -267,6 +267,7 @@ if get_option('buildtype') == 'debug'
|
||||
'tests/test_cli.c',
|
||||
'src/cli.c',
|
||||
'src/options.c',
|
||||
'src/util/log.c',
|
||||
'src/util/net.c',
|
||||
'src/util/str.c',
|
||||
'src/util/strbuf.c',
|
||||
|
@ -275,7 +275,7 @@ Configure and reconnect the device over TCP/IP.
|
||||
|
||||
If a destination address is provided, then scrcpy connects to this address before starting. The device must listen on the given TCP port (default is 5555).
|
||||
|
||||
If no destination address is provided, then scrcpy attempts to find the IP address of the current device (typically connected over USB), enables TCP/IP mode, then connects to this address before starting.
|
||||
If no destination address is provided, then scrcpy attempts to find the IP address and adb port of the current device (typically connected over USB), enables TCP/IP mode if necessary, then connects to this address before starting.
|
||||
|
||||
.TP
|
||||
.B \-S, \-\-turn\-screen\-off
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include "util/str.h"
|
||||
#endif
|
||||
#ifdef HAVE_V4L2
|
||||
# include <libavdevice/avdevice.h>
|
||||
#endif
|
||||
@ -18,8 +22,8 @@
|
||||
#include "version.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
#ifdef __WINDOWS__
|
||||
main_scrcpy(int argc, char *argv[]) {
|
||||
#ifdef _WIN32
|
||||
// disable buffering, we want logs immediately
|
||||
// even line buffering (setvbuf() with mode _IOLBF) is not sufficient
|
||||
setbuf(stdout, NULL);
|
||||
@ -80,3 +84,52 @@ main(int argc, char *argv[]) {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
#ifndef _WIN32
|
||||
return main_scrcpy(argc, argv);
|
||||
#else
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
int wargc;
|
||||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
||||
if (!wargv) {
|
||||
LOG_OOM();
|
||||
return SCRCPY_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char **argv_utf8 = malloc((wargc + 1) * sizeof(*argv_utf8));
|
||||
if (!argv_utf8) {
|
||||
LOG_OOM();
|
||||
LocalFree(wargv);
|
||||
return SCRCPY_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
argv_utf8[wargc] = NULL;
|
||||
|
||||
for (int i = 0; i < wargc; ++i) {
|
||||
argv_utf8[i] = sc_str_from_wchars(wargv[i]);
|
||||
if (!argv_utf8[i]) {
|
||||
LOG_OOM();
|
||||
for (int j = 0; j < i; ++j) {
|
||||
free(argv_utf8[j]);
|
||||
}
|
||||
LocalFree(wargv);
|
||||
free(argv_utf8);
|
||||
return SCRCPY_EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
LocalFree(wargv);
|
||||
|
||||
int ret = main_scrcpy(wargc, argv_utf8);
|
||||
|
||||
for (int i = 0; i < wargc; ++i) {
|
||||
free(argv_utf8[i]);
|
||||
}
|
||||
free(argv_utf8);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#define SC_SERVER_PATH_DEFAULT PREFIX "/share/scrcpy/" SC_SERVER_FILENAME
|
||||
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||
|
||||
#define SC_ADB_PORT_DEFAULT 5555
|
||||
|
||||
static char *
|
||||
get_server_path(void) {
|
||||
#ifdef __WINDOWS__
|
||||
@ -513,27 +515,36 @@ sc_server_on_terminated(void *userdata) {
|
||||
LOGD("Server terminated");
|
||||
}
|
||||
|
||||
static bool
|
||||
is_tcpip_mode_enabled(struct sc_server *server, const char *serial) {
|
||||
static uint16_t
|
||||
get_adb_tcp_port(struct sc_server *server, const char *serial) {
|
||||
struct sc_intr *intr = &server->intr;
|
||||
|
||||
char *current_port =
|
||||
sc_adb_getprop(intr, serial, "service.adb.tcp.port", SC_ADB_SILENT);
|
||||
if (!current_port) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Is the device is listening on TCP on port 5555?
|
||||
bool enabled = !strcmp("5555", current_port);
|
||||
long value;
|
||||
bool ok = sc_str_parse_integer(current_port, &value);
|
||||
free(current_port);
|
||||
return enabled;
|
||||
if (!ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value < 0 || value > 0xFFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool
|
||||
wait_tcpip_mode_enabled(struct sc_server *server, const char *serial,
|
||||
unsigned attempts, sc_tick delay) {
|
||||
if (is_tcpip_mode_enabled(server, serial)) {
|
||||
LOGI("TCP/IP mode enabled");
|
||||
uint16_t expected_port, unsigned attempts,
|
||||
sc_tick delay) {
|
||||
uint16_t adb_port = get_adb_tcp_port(server, serial);
|
||||
if (adb_port == expected_port) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -547,28 +558,23 @@ wait_tcpip_mode_enabled(struct sc_server *server, const char *serial,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_tcpip_mode_enabled(server, serial)) {
|
||||
LOGI("TCP/IP mode enabled");
|
||||
adb_port = get_adb_tcp_port(server, serial);
|
||||
if (adb_port == expected_port) {
|
||||
return true;
|
||||
}
|
||||
} while (--attempts);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *
|
||||
append_port_5555(const char *ip) {
|
||||
size_t len = strlen(ip);
|
||||
|
||||
// sizeof counts the final '\0'
|
||||
char *ip_port = malloc(len + sizeof(":5555"));
|
||||
if (!ip_port) {
|
||||
static char *
|
||||
append_port(const char *ip, uint16_t port) {
|
||||
char *ip_port;
|
||||
int ret = asprintf(&ip_port, "%s:%" PRIu16, ip, port);
|
||||
if (ret == -1) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ip_port, ip, len);
|
||||
memcpy(ip_port + len, ":5555", sizeof(":5555"));
|
||||
|
||||
return ip_port;
|
||||
}
|
||||
|
||||
@ -586,34 +592,36 @@ sc_server_switch_to_tcpip(struct sc_server *server, const char *serial) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ip_port = append_port_5555(ip);
|
||||
free(ip);
|
||||
if (!ip_port) {
|
||||
return NULL;
|
||||
}
|
||||
uint16_t adb_port = get_adb_tcp_port(server, serial);
|
||||
if (adb_port) {
|
||||
LOGI("TCP/IP mode already enabled on port %" PRIu16, adb_port);
|
||||
} else {
|
||||
LOGI("Enabling TCP/IP mode on port " SC_STR(SC_ADB_PORT_DEFAULT) "...");
|
||||
|
||||
bool tcp_mode = is_tcpip_mode_enabled(server, serial);
|
||||
|
||||
if (!tcp_mode) {
|
||||
bool ok = sc_adb_tcpip(intr, serial, 5555, SC_ADB_NO_STDOUT);
|
||||
bool ok = sc_adb_tcpip(intr, serial, SC_ADB_PORT_DEFAULT,
|
||||
SC_ADB_NO_STDOUT);
|
||||
if (!ok) {
|
||||
LOGE("Could not restart adbd in TCP/IP mode");
|
||||
goto error;
|
||||
free(ip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned attempts = 40;
|
||||
sc_tick delay = SC_TICK_FROM_MS(250);
|
||||
ok = wait_tcpip_mode_enabled(server, serial, attempts, delay);
|
||||
ok = wait_tcpip_mode_enabled(server, serial, SC_ADB_PORT_DEFAULT,
|
||||
attempts, delay);
|
||||
if (!ok) {
|
||||
goto error;
|
||||
free(ip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
adb_port = SC_ADB_PORT_DEFAULT;
|
||||
LOGI("TCP/IP mode enabled on port " SC_STR(SC_ADB_PORT_DEFAULT));
|
||||
}
|
||||
|
||||
char *ip_port = append_port(ip, adb_port);
|
||||
free(ip);
|
||||
return ip_port;
|
||||
|
||||
error:
|
||||
free(ip_port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -640,7 +648,8 @@ sc_server_configure_tcpip_known_address(struct sc_server *server,
|
||||
const char *addr) {
|
||||
// Append ":5555" if no port is present
|
||||
bool contains_port = strchr(addr, ':');
|
||||
char *ip_port = contains_port ? strdup(addr) : append_port_5555(addr);
|
||||
char *ip_port = contains_port ? strdup(addr)
|
||||
: append_port(addr, SC_ADB_PORT_DEFAULT);
|
||||
if (!ip_port) {
|
||||
LOG_OOM();
|
||||
return false;
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Stringify a numeric value */
|
||||
#define SC_STR(s) SC_XSTR(s)
|
||||
#define SC_XSTR(s) #s
|
||||
|
||||
/**
|
||||
* Like strncpy(), except:
|
||||
* - it copies at most n-1 chars
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "thread.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <SDL2/SDL_thread.h>
|
||||
|
||||
#include "log.h"
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Adapted from vlc_vector:
|
||||
// <https://code.videolan.org/videolan/vlc/-/blob/0857947abaed9c89810cd96353aaa1b7e6ba3b0d/include/vlc_vector.h>
|
||||
|
@ -22,4 +22,4 @@ ffmpeg_avutil = 'avutil-56'
|
||||
prebuilt_ffmpeg = 'ffmpeg-win32-4.3.1'
|
||||
prebuilt_sdl2 = 'SDL2-2.0.22/i686-w64-mingw32'
|
||||
prebuilt_libusb_root = 'libusb-1.0.26'
|
||||
prebuilt_libusb = prebuilt_libusb_root + '/MinGW-Win32'
|
||||
prebuilt_libusb = 'libusb-1.0.26/MinGW-Win32'
|
||||
|
@ -22,4 +22,4 @@ ffmpeg_avutil = 'avutil-57'
|
||||
prebuilt_ffmpeg = 'ffmpeg-win64-5.0.1'
|
||||
prebuilt_sdl2 = 'SDL2-2.0.22/x86_64-w64-mingw32'
|
||||
prebuilt_libusb_root = 'libusb-1.0.26'
|
||||
prebuilt_libusb = prebuilt_libusb_root + '/MinGW-x64'
|
||||
prebuilt_libusb = 'libusb-1.0.26/MinGW-x64'
|
||||
|
@ -21,7 +21,7 @@ public final class DisplayManager {
|
||||
// public to call it from unit tests
|
||||
public static DisplayInfo parseDisplayInfo(String dumpsysDisplayOutput, int displayId) {
|
||||
Pattern regex = Pattern.compile(
|
||||
"^ mOverrideDisplayInfo=DisplayInfo\\{\".*?\", displayId " + displayId + ".*?(, FLAG_.*)?, real ([0-9]+) x ([0-9]+).*?, "
|
||||
"^ mOverrideDisplayInfo=DisplayInfo\\{\".*?, displayId " + displayId + ".*?(, FLAG_.*)?, real ([0-9]+) x ([0-9]+).*?, "
|
||||
+ "rotation ([0-9]+).*?, layerStack ([0-9]+)",
|
||||
Pattern.MULTILINE);
|
||||
Matcher m = regex.matcher(dumpsysDisplayOutput);
|
||||
|
@ -183,4 +183,60 @@ public class CommandParserTest {
|
||||
Assert.assertEquals(1080, displayInfo.getSize().getWidth());
|
||||
Assert.assertEquals(2280, displayInfo.getSize().getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDisplayInfoFromDumpsysDisplayAPI29WithNoFlags() {
|
||||
/* @formatter:off */
|
||||
String partialOutput = "Logical Displays: size=2\n"
|
||||
+ " Display 0:\n"
|
||||
+ " mDisplayId=0\n"
|
||||
+ " mLayerStack=0\n"
|
||||
+ " mHasContent=true\n"
|
||||
+ " mAllowedDisplayModes=[1]\n"
|
||||
+ " mRequestedColorMode=0\n"
|
||||
+ " mDisplayOffset=(0, 0)\n"
|
||||
+ " mDisplayScalingDisabled=false\n"
|
||||
+ " mPrimaryDisplayDevice=Built-in Screen\n"
|
||||
+ " mBaseDisplayInfo=DisplayInfo{\"Built-in Screen, displayId 0\", uniqueId \"local:0\", app 3664 x 1920, "
|
||||
+ "real 3664 x 1920, largest app 3664 x 1920, smallest app 3664 x 1920, mode 61, defaultMode 61, modes ["
|
||||
+ "{id=1, width=3664, height=1920, fps=60.000004}, {id=2, width=3664, height=1920, fps=61.000004}, "
|
||||
+ "{id=61, width=3664, height=1920, fps=120.00001}], colorMode 0, supportedColorModes [0], "
|
||||
+ "hdrCapabilities android.view.Display$HdrCapabilities@4a41fe79, rotation 0, density 290 (320.842 x 319.813) dpi, "
|
||||
+ "layerStack 0, appVsyncOff 1000000, presDeadline 8333333, type BUILT_IN, address {port=129, model=0}, "
|
||||
+ "state ON, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS, removeMode 0}\n"
|
||||
+ " mOverrideDisplayInfo=DisplayInfo{\"Built-in Screen, displayId 0\", uniqueId \"local:0\", app 3664 x 1920, "
|
||||
+ "real 3664 x 1920, largest app 3664 x 3620, smallest app 1920 x 1876, mode 61, defaultMode 61, modes ["
|
||||
+ "{id=1, width=3664, height=1920, fps=60.000004}, {id=2, width=3664, height=1920, fps=61.000004}, "
|
||||
+ "{id=61, width=3664, height=1920, fps=120.00001}], colorMode 0, supportedColorModes [0], "
|
||||
+ "hdrCapabilities android.view.Display$HdrCapabilities@4a41fe79, rotation 0, density 290 (320.842 x 319.813) dpi, "
|
||||
+ "layerStack 0, appVsyncOff 1000000, presDeadline 8333333, type BUILT_IN, address {port=129, model=0}, "
|
||||
+ "state ON, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS, removeMode 0}\n"
|
||||
+ " Display 31:\n"
|
||||
+ " mDisplayId=31\n"
|
||||
+ " mLayerStack=31\n"
|
||||
+ " mHasContent=true\n"
|
||||
+ " mAllowedDisplayModes=[92]\n"
|
||||
+ " mRequestedColorMode=0\n"
|
||||
+ " mDisplayOffset=(0, 0)\n"
|
||||
+ " mDisplayScalingDisabled=false\n"
|
||||
+ " mPrimaryDisplayDevice=PanelLayer-#main\n"
|
||||
+ " mBaseDisplayInfo=DisplayInfo{\"PanelLayer-#main, displayId 31\", uniqueId "
|
||||
+ "\"virtual:com.test.system,10040,PanelLayer-#main,0\", app 800 x 110, real 800 x 110, largest app 800 x 110, smallest app 800 x "
|
||||
+ "110, mode 92, defaultMode 92, modes [{id=92, width=800, height=110, fps=60.0}], colorMode 0, supportedColorModes [0], "
|
||||
+ "hdrCapabilities null, rotation 0, density 200 (200.0 x 200.0) dpi, layerStack 31, appVsyncOff 0, presDeadline 16666666, "
|
||||
+ "type VIRTUAL, state ON, owner com.test.system (uid 10040), FLAG_PRIVATE, removeMode 1}\n"
|
||||
+ " mOverrideDisplayInfo=DisplayInfo{\"PanelLayer-#main, displayId 31\", uniqueId "
|
||||
+ "\"virtual:com.test.system,10040,PanelLayer-#main,0\", app 800 x 110, real 800 x 110, largest app 800 x 800, smallest app 110 x "
|
||||
+ "110, mode 92, defaultMode 92, modes [{id=92, width=800, height=110, fps=60.0}], colorMode 0, supportedColorModes [0], "
|
||||
+ "hdrCapabilities null, rotation 0, density 200 (200.0 x 200.0) dpi, layerStack 31, appVsyncOff 0, presDeadline 16666666, "
|
||||
+ "type VIRTUAL, state OFF, owner com.test.system (uid 10040), FLAG_PRIVATE, removeMode 1}\n";
|
||||
DisplayInfo displayInfo = DisplayManager.parseDisplayInfo(partialOutput, 31);
|
||||
Assert.assertNotNull(displayInfo);
|
||||
Assert.assertEquals(31, displayInfo.getDisplayId());
|
||||
Assert.assertEquals(0, displayInfo.getRotation());
|
||||
Assert.assertEquals(31, displayInfo.getLayerStack());
|
||||
Assert.assertEquals(0, displayInfo.getFlags());
|
||||
Assert.assertEquals(800, displayInfo.getSize().getWidth());
|
||||
Assert.assertEquals(110, displayInfo.getSize().getHeight());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user