Commit graph

303 commits

Author SHA1 Message Date
Romain Vimont
5ebf31d483 Remove useless screen render on initialization
screen_render() should not be called on initialization:
 1. it is useless, since the window is hidden until the first frame;
 2. it writes an empty texture (probably green) to the renderer.
2018-02-15 13:42:31 +01:00
Romain Vimont
d977202224 Add Ctrl+i shortcut to enable/disable FPS counter
Disable FPS counter on start, and use Ctrl+i to enable/disable it.
2018-02-15 12:24:16 +01:00
Romain Vimont
000ced9ba8 Refactor screencontrol to inputmanager
The "screen control" handled user input, which happened to be only
used to control the screen.

The controller and screen were passed to every function. Instead, group
them in a struct input_manager.

The purpose is to add a new shortcut to enable/disable FPS counter. This
feature is not related to "screen control", and will require access to
the "frames" instance.
2018-02-15 12:07:47 +01:00
Romain Vimont
42882702d7 Expose skip_frames as a build option
It can be initially configured by:

    meson builddir -Dskip_frames=false

Or on an existing builddir by:

    mesonconf builddir -Dskip_frames=false
2018-02-15 11:24:18 +01:00
Romain Vimont
38e6682875 Add FPS counter
Remove frame counter from scrcpy.c and add a new FPS counter, logging as
INFO the measured frame rate every second (on new frame).
2018-02-15 11:22:48 +01:00
Romain Vimont
c6c17af840 Do not print usage on command error
On error, a message is printed. If we print usage afterwards, it's easy
to miss it.
2018-02-14 19:01:26 +01:00
Romain Vimont
8697659890 Expose device serial as an optional argument
The device serial was provided as a positional argument:

    scrcpy 0123456789abcdef

Instead, expose it as an optional argument, -s or --serial:

    scrcpy -s 0123456789abcdef

This avoids inconsistency between platforms when the positional
argument is passed before the options (which is undefined).
2018-02-14 18:57:29 +01:00
Romain Vimont
23d92a95b6 Extract argument parsing to specific functions
To avoid a big switch/case, implement the argument parsing logic in
separate static functions.
2018-02-14 18:53:16 +01:00
Romain Vimont
111068d733 Use SDL_bool return to indicate success
For clarity and consistency across the application, return SDL_TRUE
(instead of 0) on success and SDL_FALSE on failure (instead of
non-zero).
2018-02-14 18:44:28 +01:00
Romain Vimont
d3c76c004e Sort parameters by letter
For readability, sort the command-line arguments parsing by letter.
2018-02-14 18:39:46 +01:00
Romain Vimont
0efa9305eb Require Meson 0.37
Older versions of Meson are too limited, and it's simple to install a
newer version ("pip3 install meson").
2018-02-14 14:03:56 +01:00
Romain Vimont
c2127d0819 Replace meson subprojects by subdir
Since Meson 0.44, subproject_dir may not be '.' anymore. This implies we
must move app/ and server/ to a subprojects/ directory, which requires
to also change some gradle files.

Instead, just use subdir(), with options to disable building of the app
or the server.
2018-02-14 14:03:56 +01:00
Romain Vimont
ff94462d8a Refactor build system
The client was built with Meson, the server with Gradle, and were run by
a Makefile.

Add a Meson script for the server (which delegates to Gradle), and a
parent script to build and install both the client and the server to the
system, typically with:

    meson --buildtype release build
    cd build
    ninja
    sudo ninja install

In addition, use a separate Makefile to build a "portable" version of
the application (where the client expects the server to be in the
current directory). Typically:

    make release-portable
    cd dist/scrcpy
    ./scrcpy

This is especially useful for Windows builds, which are not "installed".
2018-02-14 09:23:14 +01:00
Romain Vimont
396df8a9d8 Provide config.h.in for old meson versions
The current meson version is able to generate a config.h from a
configuration data object without any template.

However, older versions of meson require a template, so provide it for
compatibility.
2018-02-13 10:24:02 +01:00
Romain Vimont
3ed80a1fac Define macros wrappers for logs
Use macros to wrap SDL_Log* functions with the "application" category.
2018-02-13 10:10:18 +01:00
Romain Vimont
d45ef1a295 Do not use too recent set_quoted()
Old versions of meson do not support set_quoted(). Replace the call by
the old-fashioned manual quotation.
2018-02-12 17:27:25 +01:00
Romain Vimont
ad41bacb48 Fix "terminate process" on Windows
CloseHandle() does not terminate the process. TerminateProcess() does.
2018-02-12 16:35:23 +01:00
Romain Vimont
6fe65d9f5c Log with category APPLICATION
All our logs should use APPLICATION category. The logs for other
categories are not printed by default under the "critical" level.
2018-02-12 16:09:34 +01:00
Romain Vimont
4dbc450d01 Enable debug logs only for debug builds
In release mode, use the default log priorities.
2018-02-12 14:17:29 +01:00
Romain Vimont
0fce4f95b9 Properly clean up on exit
The SDL clean up does not crash anymore on exit, probably since the
memory corruption caused by calling SDLNet_TCP_Close() too early has
been resolved.
2018-02-09 16:21:10 +01:00
Romain Vimont
eb09fefd43 Timeout the server socket connection
Wait no more than 2 seconds for accepting the connection from the
device, since it blocks the event loop, preventing to react to SIGTERM
(Ctrl+C).
2018-02-09 16:21:10 +01:00
Romain Vimont
90a46b4c45 Improve startup time
On startup, the client has to:
 1. listen on a port
 2. push and start the server to the device
 3. wait for the server to connect (accept)
 4. read device name and size
 5. initialize SDL
 6. initialize the window and renderer
 7. show the window

From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.

Once complete, the client initializes SDL, which takes ~500ms.

These two expensive actions are executed sequentially:

                     HOST              DEVICE
listen on port        |                  |
push/start the server |----------------->|| app_process loads the jar
accept the connection .   ^              ||
                      .   |              ||
                      .   | WASTE        ||
                      .   |  OF          ||
                      .   | TIME         ||
                      .   |              ||
                      .   |              ||
                      .   v              X execution of our java main
connection accepted   |<-----------------| connect to the host
init SDL             ||                  |
                     || ,----------------| send frames
                     || |,---------------|
                     || ||,--------------|
                     || |||,-------------|
                     || ||||,------------|
init window/renderer  | |||||,-----------|
display frames        |<++++++-----------|
(many frames skipped)

The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).

But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):

                     HOST              DEVICE
listen on port        |                  |
push/start the server |----------------->||app_process loads the jar
init SDL             ||                  ||
                     ||                  ||
                     ||                  ||
                     ||                  ||
                     ||                  ||
                     ||                  ||
accept the connection .                  ||
                      .                  X execution of our java main
connection accepted   |<-----------------| connect to the host
init window/renderer  |                  |
display frames        |<-----------------| send frames
                      |<-----------------|

In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).

Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 16:19:50 +01:00
Romain Vimont
523097eadf Provide decoder_init()
Expose an initializer so that the caller does not have to guess what
fields must be initialized.
2018-02-09 13:30:49 +01:00
Romain Vimont
4662198261 Do not release TCP sockets while still in use
SDLNet_TCP_Close() not only closes, but also release the resources.

Therefore, we must not close the socket if another thread attempts to
read it.

For that purpose, move socket closing from server_stop() to
server_destroy().
2018-02-09 12:59:36 +01:00
Romain Vimont
fe21d9dfb5 Move frame updating to screen.c
Replace screen_update() by a higher-level screen_update_frame() handling
the whole frame updating, so that scrcpy.c just call it without managing
implementation details.
2018-02-09 11:14:47 +01:00
Romain Vimont
7458d8271e Kill the server immediately on close
Do not wait 100ms anymore to let the server print any exception: we
justly want to ignore them.

Moreover, there is no nanosleep() on Windows, so this solve another
problem.
2018-02-09 11:01:50 +01:00
Romain Vimont
2fdc368c41 Do not try to decode video when EOF is reached
When the video stream socket is closed and read_packey() returns -1,
av_read_frame() still returns 0.

To detect EOF, check the flag eof_reached in the AVIOContext.

This avoids garbage errors on closing.
2018-02-09 09:57:23 +01:00
Romain Vimont
a8aa3d39b7 Send "screen on" command only on mouse down
Avoid to send the command twice, once on mouse down, once on mouse up.
2018-02-09 09:43:58 +01:00
Romain Vimont
127e56780a Fix deadlock on exit if SKIP_FRAMES disabled
On exit, the renderer will not consume frames anymore, so signal the
condition variable to wake up the decoder.
2018-02-09 09:41:05 +01:00
Romain Vimont
629c296207 Move frame swapping logic to frame.c
Expose frames_offer_decoded_frame() and frames_consume_rendered_frame()
so that callers are not exposed to frame swapping (between the decoding
and rendering frames) details.
2018-02-08 20:57:29 +01:00
Romain Vimont
0d7f050389 Unlock mutex on screen update failure
The mutex was not unlocked on all code paths.
2018-02-08 18:39:38 +01:00
Romain Vimont
e8dfb723af Move control-related code to screencontrol.c
Move the code handling user input from scrcpy.c to a separate file,
screencontrol.c.
2018-02-08 18:14:50 +01:00
Romain Vimont
e1749a0c09 Remove the "adb reverse" tunnel immediately
As soon as we accepted a connection, we can remove the "adb reverse"
tunnel.
2018-02-08 17:40:09 +01:00
Romain Vimont
3b06e7d500 Move device-related code to device.c
Move the code to read the initial device info from scrcpy.c to a
separate file, device.c.
2018-02-08 17:40:09 +01:00
Romain Vimont
28c5cc030b Move server-related code to server.c
The file server.c already existed, but exposed a low-level API. Make it
higher-level, so that scrcpy.c does not handle server details directly.
2018-02-08 17:40:09 +01:00
Romain Vimont
6c578b5caa Move screen-related code to screen.c
The file scrcpy.c contains too many different things in addition to the
main logic, so move the screen code to a separate file, screen.c.
2018-02-08 15:43:28 +01:00
Romain Vimont
14c58546a7 Add missing include guards
In practice, these headers are included only once, but it's a good
practice to always use include guards.
2018-02-08 15:26:08 +01:00
Romain Vimont
ffae15e36a Rename control to controller
The struct decoder is defined in decoder.h.

For naming consistency, define the struct controller in controller.h.
2018-02-08 13:26:01 +01:00
Romain Vimont
7b7fd77134 Add missing static
Some functions in scrcpy.c are not used outside the file, so declare
them static.
2018-02-08 09:08:55 +01:00
Romain Vimont
f39de46a39 Add delay before stopping server
Let some time to print any exception trace before killing it.
2018-02-07 15:41:59 +01:00
Romain Vimont
cb1428223f Log user request to quit
Log at debug level user requests to quit.
2018-02-07 15:41:59 +01:00
Romain Vimont
7fe11033cb Include dependencies version
On --version, also print the dependencies version scrcpy has been
compiled against.
2018-02-07 15:41:59 +01:00
Romain Vimont
9f6464acff Expose application version
Expose scrcpy version via -v or --version.
2018-02-07 15:41:59 +01:00
Romain Vimont
8d30d40b79 Make SKIP_FRAMES a compilation flag
The skip_frames flag was a non-configurable runtime flag. Since it is
not exposed to the user, there is no need for a (possible) runtime cost.

For testing purpose, we still want it to be configurable, so make it a
compilation flag.
2018-02-07 15:40:24 +01:00
Romain Vimont
53ff1aa410 Use meson to configure default values
Make meson generate config.h with configured values.
2018-02-07 12:09:10 +01:00
Romain Vimont
cb7e29180f Change the window icon color in debug mode
To highlight the debug/release mode of the running application, use a
different window icon color in debug mode.
2018-02-07 11:48:25 +01:00
Romain Vimont
71c2bfdd22 Parse XPM without SDL_image
We encounter some problems with SDL2_image on MSYS2 (Windows), so
implement our own XPM parsing which does not depend on SDL_image.

The input XPM is considered safe (it's in our source repo), so do not
check XPM format errors. This implies that read_xpm() is not safe to
call on any unsafe input.

Although less straightforward, use SDL_CreateRGBSurfaceFrom() instead of
SDL_CreateRGBSurfaceWithFormatFrom() because it is available with SDL
versions older than 2.0.5.
2018-02-05 19:24:33 +01:00
Romain Vimont
f22d4decca Enable mouse focus clickthrough only if available
The hint SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH appeared in SDL 2.0.5. Ignore
it if the SDL version is older.
2018-02-05 16:15:52 +01:00
Romain Vimont
52c89c7afb Add window icon
Add a bugdroid icon loaded from an XPM.
2018-02-05 14:46:00 +01:00
Romain Vimont
5eb91a4ca7 Fix scrcpy() return value
The scrcpy() function returns a SDL_bool to indicate its success, but
was initialized to 0 (SDL_FALSE) instead of SDL_TRUE.
2018-02-04 12:39:17 +01:00
Romain Vimont
69a359c7f4 Refactor actions calls
The purpose of handle_shortcut() was to group all actions together,
whether they are initiated from a text input event or a keycode event.

However, it did not handle the case where it was initiated from a mouse
event (a right-click must turn the screen on), since the action was
identified by the shortcut char.

Instead, expose one function per action, to be called directly from
where the event is handled.
2018-02-02 15:23:04 +01:00
Romain Vimont
d73dee9833 fixup! Handle all shortcuts in the same function 2018-02-02 15:17:03 +01:00
Romain Vimont
0a70e24e80 Add new shortcuts description in help
Document the new shortcuts in the help (scrcpy --help).
2018-02-02 15:10:44 +01:00
Romain Vimont
a139509f11 Turn screen on on right-click
The right-click is almost useless on Android, so use it to turn the
screen on.

Add a new control event type (command) to request the server to turn the
screen on.
2018-02-02 14:56:03 +01:00
Romain Vimont
deba69d022 Handle all shortcuts in the same function
Shortcuts are sometimes initiated from a keycode event, and sometimes
from a text input event.

Move the handling to a unique function.
2018-02-02 12:01:38 +01:00
Romain Vimont
7f6a565401 Extract shortcut actions to separate functions
To simplify event handling code, move all actions to separate functions.
2018-02-02 11:52:19 +01:00
Romain Vimont
f8ad007a28 Move switch fullscreen logs
Logs were printed by the caller of switch_fullscreen(). Move them inside
the function to simplify event handling code.
2018-02-02 11:48:05 +01:00
Romain Vimont
6fe7b84629 Add shortcuts for physical keys
Add shortcuts for HOME, BACK, APPS, POWER, VOLUME_UP and VOLUME_DOWN.
2018-02-02 11:39:25 +01:00
Romain Vimont
1faf6cfd9d Rename the server scrcpy-server.jar
The server is built as an APK to simplify the build, but in fact this is
a simple jar (it is not even signed).

In order to avoid confusion, rename it to .jar, so that users do not try
to "adb install" it.

Also rename it from "scrcpy" to "scrcpy-server" to distinguish from the
client-side.
2018-02-02 09:37:10 +01:00
Romain Vimont
2172c53b7b Force the server target filename
The server path may be customized using SCRCPY_APK. If its basename is
different from "scrcpy.apk", it will be pushed with a different name,
so the execution would fail.

Therefore, force the push target filename.
2018-02-02 09:34:52 +01:00
Romain Vimont
ca44585f96 Do not send simple mouse move events
Moving the mouse without any button pressed has no effect on Android.
Therefore, do not even send these very frequent events.
2018-02-02 09:26:25 +01:00
Romain Vimont
79b28eb68f Enable mouse focus clickthrough
Consider a click to gain focus as a click on the device.
2018-02-01 20:52:44 +01:00
Romain Vimont
6b546a87ab Add bit-rate command-line option
Add a command-line option (-b/--bit-rate) to customize the video
bit-rate.
2018-02-01 17:11:40 +01:00
Romain Vimont
7fe7bbf58c Check empty string before strtol()
There is no need to call strtol() if the input string is empty.
2018-02-01 17:11:40 +01:00
Romain Vimont
3bc63708b4 Remove useless newlines in SDL_Log*
Trailing new line is not necessary in SDL_Log* methods.
2018-02-01 17:11:40 +01:00
Romain Vimont
2683fa20ed Add debug log for shortcuts
Add a debug log for every succeeded shortcut action.
2018-02-01 17:11:40 +01:00
Romain Vimont
274e1ac9ec Fix rotation bug in fullscreen mode on X11
On rotation, scrcpy resize the window to match the new rotation.
However, in fullscreen mode, setting the window size does not change the
windowed size on X11, so the behavior is incorrect.

To avoid the problem, apply the resize only after fullscreen is
disabled.
2018-02-01 17:11:40 +01:00
Romain Vimont
35a111d56e Add --help
Provide command-line help, with -h/--help option.
2018-02-01 17:11:40 +01:00
Romain Vimont
ee93f3f23a Rename maximum_size to max_size
The long option is --max-size, so for consistency, adapt the code
accordingly.
2018-02-01 17:11:40 +01:00
Romain Vimont
213b721ff9 Use long command-line options
In addition to the short form (e.g. "-p"), add the long form ("--port").
2018-02-01 15:35:20 +01:00
Romain Vimont
60b2f2ca64 Indent switch blocks content
For readability, indent "case" in switch blocks.

Replace:

    switch (x) {
    case 1:
        // ...
    case 2:
        // ...
    case 3: { // a local scope block
        int i = 42;
        // ...
    }
    }

By:

    switch (x) {
        case 1:
            // ...
        case 2:
            // ...
        case 3: { // a local scope block
            int i = 42;
            // ...
        }
    }
2018-02-01 11:44:20 +01:00
Romain Vimont
628f88ab89 Use ADB environment variable
Use the ADB environment variable to provide a custom adb path.
2018-01-31 19:51:43 +01:00
Romain Vimont
b67907e24e Convert server to an Android project
To simplify the device server-side build, use gradle to create an APK,
even if we use it as a simple jar, by running its main() method.
2018-01-30 12:01:36 +01:00
Romain Vimont
89f6a3cfe7 Handle resized video stream
Accept a parameter to limit the video size.

For instance, with "-m 960", the great side of the video will be scaled
down to 960 (if necessary), while the other side will be scaled down so
that the aspect ratio is preserved. Both dimensions must be a multiple
of 8, so black bands might be added, and the mouse positions must be
computed accordingly.
2018-01-29 15:40:33 +01:00
Romain Vimont
879941355d Swap position/point names
A point is a 2D vector. A position represent a point relative to the
screen size.
2018-01-29 14:52:22 +01:00
Romain Vimont
2aa15db210 Add shortcut to resize to ratio 1:1
Make Ctrl+g resize the window to the size of the video (pixel-perfect).
2018-01-24 09:56:42 +01:00
Romain Vimont
ab2c3de9f5 Capture all Ctrl events
For consistency, capture all Ctrl events (not only those we react to).
2018-01-24 09:53:09 +01:00
Romain Vimont
2c35220618 Rename screen -> scrcpy -> main
Rename scrcpy.c to main.c (this file handles the command line parsing),
and screen.c to scrcpy.c (it exposes the entry point scrcpy()).
2018-01-23 16:44:59 +01:00
Romain Vimont
8984c1a7c4 Scale mouse events
The video screen size on the client may differ from the real device
screen size (e.g. the video stream may be scaled down). As a
consequence, mouse events must be scaled to match the real device
coordinates.

For this purpose, make the client send the video screen size along with
the absolute pointer location, and the server scale the location to
match the real device size before injecting mouse events.
2018-01-23 16:44:59 +01:00
Romain Vimont
d7b00a9bab Move server-related functions to server.c
In addition to the functions to start/stop the server, move the
functions to push the jar and enable/disable the "adb reverse" tunnel.
2018-01-23 16:20:03 +01:00
Romain Vimont
7d67696b7e Extract server-related functions
To lighten screen.c, move start_server() and stop_server() to a separate
file.
2018-01-22 11:29:44 +01:00
Romain Vimont
52af91f6b0 Add unit tests for control event serialization
Test serialization of the 4 types of events (keycode, text, mouse,
scroll).
2018-01-19 16:55:39 +01:00
Romain Vimont
90c69d2c79 Use pointers-to-const where relevant
Explicitly declare const a function parameter intended to be read-only.
2018-01-19 15:13:38 +01:00
Romain Vimont
53cd59605a Ignore keycodes generating unwanted events
Ctrl, Alt, Shift and Meta should not be transmitted to the Android
device: they may generate unwanted events. For instance, resizing the
window using Alt+click will generate an Alt event which may open a menu
on the device.

All keycodes that generate a text input must also be excluded, to avoid
the text input to be written twice.
2018-01-19 14:09:15 +01:00
Romain Vimont
66b7a99db6 Fix includes windows-specific source
The header strutil.h is two levels above sys/win/command.c, and
SDL_log.h was missing.
2018-01-19 11:15:51 +01:00
Romain Vimont
f75c404a26 Add tests for strutil
Test our custom string handling functions.
2018-01-18 17:25:13 +01:00
Romain Vimont
cabb102a04 Implement keyboard/mouse control
To control the device from the computer:
 - retrieve mouse and keyboard SDL events;
 - convert them to Android events;
 - serialize them;
 - send them on the same socket used by the video stream (but in the
 opposite direction);
 - deserialize the events on the Android side;
 - inject them using the InputManager.
2018-01-18 17:25:13 +01:00
Romain Vimont
95591d2938 Move platform specific to sys/
Move unix/ and win/ to sys/, so that we can use android/ for android
headers without confusion.
2018-01-04 10:22:09 +01:00
Romain Vimont
a919944372 Use _exit() instead of exit() in child process
exit() should not be called from within a child process, since it would
call functions registered with atexit(), and flush stdio streams. Use
_exit() instead.
2018-01-04 10:22:09 +01:00
Romain Vimont
07b3918129 Do not call SDL_Quit()
It may crash in i965_dri.so when calling SDL_Quit (probably a driver
bug). To avoid a segmentation fault, do not call SDL_Quit().
2017-12-19 14:12:11 +01:00
Romain Vimont
a005df7b37 Always destroy in reverse order
For consistency and safety, always destroy objects in reverse order they
were initialized.
2017-12-19 14:11:55 +01:00
Romain Vimont
de106747b6 Improve main() error handling
Parse the command-line arguments first, and do not ignore avformat
network init failure. At the end, deinit the avformat network.
2017-12-18 11:29:34 +01:00
Romain Vimont
bb8afa9324 Fix comment about data sent over the socket
We now send the device name in addition to the screen dimensions on the
socket. Update the comment accordingly.
2017-12-18 11:27:55 +01:00
Romain Vimont
d972a88c1a Optimize includes
Only include SDL_stdinc.h for SDL_bool, not the whole SDL.h.
2017-12-18 11:07:42 +01:00
Romain Vimont
d5b349f670 Do not inline lockutil functions
This duplicates chars in the final binary.
2017-12-18 11:07:42 +01:00
Romain Vimont
a9b276aa67 Remove useless forward declarations
The required headers are included anyway.
2017-12-15 17:19:43 +01:00
Romain Vimont
b9c9466d65 Handle condition variable failure
Add condition variables function wrappers to handle unexpected failure.
2017-12-15 17:15:55 +01:00
Romain Vimont
c4266e487b Rename (un)lock_mutex to mutex_(un)lock
For consistency, rename lock_mutex and unlock_mutex to mutex_lock and
mutex_unlock.
2017-12-15 17:15:55 +01:00
Romain Vimont
ad667bfa20 Fix function signature
Use void for parameters (this project is in C).
2017-12-15 11:37:29 +01:00
Romain Vimont
37d88b8a6a Use SDL_bool return type instead of int
Many functions returned an int to indicate their success. For clarity,
use SDL_bool instead.
2017-12-15 11:27:54 +01:00
Romain Vimont
2b44052f80 Destroy condition variable on frames destruction
A condition variable was init for the "struct frames", but was never destroyed.
2017-12-15 11:12:02 +01:00
Romain Vimont
39fd6ce518 Send device name on the socket
Make the server send the device name along with the width and height, so
that the client may use it as the window title.
2017-12-13 10:02:07 +01:00
Romain Vimont
54d9148a36 Initial commit
Start a new clean history from here.
2017-12-12 15:25:15 +01:00