This allows to execute all adb commands with the specific -s parameter,
even if it is not provided by the user.
In practice, calling adb without -s works if there is exactly one device
connected. But some adb commands (for example "adb push" on drag & drop)
could be executed after another device is connected, so the actual
device serial must be known.
The interruptible version of the function to check process success
(sc_process_check_success_intr()) did not accept a close parameter to
avoid a race condition. But as the result, the processes were not closed
at all.
Add a close parameter, and close the process separately to avoid the
race condition.
Interrupt any blocking call on process terminated, like on
server_stop().
This allows to interrupt any blocking accept() with correct
synchronization without additional complexity.
Define server callbacks, start the server asynchronously and listen to
connection events to initialize scrcpy properly.
It will help to simplify the server code, and allows to run the UI event
loop while the server is connecting. In particular, this will allow to
receive SIGINT/Ctrl+C events during connection to interrupt immediately.
Currently, server_stop() is called from the same thread as
server_connect_to(), so interruption may never happen.
This is a step to prepare executing the server from a dedicated thread.
Use the option descriptions to generate the optstring and longopts
parameters for the getopt_long() command.
That way, the options are completely described in a single place.
On Linux, socket functions are unblocked by shutdown(), but on Windows
they are unblocked by closesocket().
Expose net_interrupt() and net_close() to abstract these differences:
- net_interrupt() calls shutdown() on Linux and closesocket() on
Windows (if not already called);
- net_close() calls close() on Linux and closesocket() on Windows (if
not already called).
This simplifies the server code, and prevents a data race on close
(reported by TSAN) on Linux (but does not fix it on Windows):
WARNING: ThreadSanitizer: data race (pid=836124)
Write of size 8 at 0x7ba0000000d0 by main thread:
#0 close ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1690 (libtsan.so.0+0x359d8)
#1 net_close ../app/src/util/net.c:211 (scrcpy+0x1c76b)
#2 close_socket ../app/src/server.c:330 (scrcpy+0x19442)
#3 server_stop ../app/src/server.c:522 (scrcpy+0x19e33)
#4 scrcpy ../app/src/scrcpy.c:532 (scrcpy+0x156fc)
#5 main ../app/src/main.c:92 (scrcpy+0x622a)
Previous read of size 8 at 0x7ba0000000d0 by thread T6:
#0 recv ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:6603 (libtsan.so.0+0x4f4a6)
#1 net_recv ../app/src/util/net.c:167 (scrcpy+0x1c5a7)
#2 run_receiver ../app/src/receiver.c:76 (scrcpy+0x12819)
#3 <null> <null> (libSDL2-2.0.so.0+0x84f40)
When Ctrl+v is pressed, a control is sent to the device to set the
device clipboard before injecting Ctrl+v.
With the InputManager method, it is guaranteed that the device
synchronization is executed before handling Ctrl+v, since the commands
are executed on the device in sequence.
However, HID are injected from the computer, so there is no such
guarantee. As a consequence, on Android, Ctrl+v triggers a paste with
the old clipboard content.
To workaround the issue, wait a bit (2 milliseconds) from the AOA
thread before injecting the event, to leave enough time for the
clipboard to be set before injecting Ctrl+v.
When an AOA HID keyboard is registered, CAPSLOCK and NUMLOCK are both
disabled, regardless of the state of the computer keyboard.
To synchronize the state, on first key event, inject CAPSLOCK and/or
NUMLOCK if necessary.
The serial is necessary to find the correct Android device for AOA.
If it is not explicitly provided by the user via -s, then execute "adb
getserialno" to retrieve it.
The AVOutputFormat name is a comma-separated list. In theory, possible
names for V4L2 are:
- "video4linux2,v4l2"
- "v4l2,video4linux2"
- "v4l2"
- "video4linux2"
To find the muxer in all cases, we must request exactly one muxer name
at a time.
PR #2718 <https://github.com/Genymobile/scrcpy/pull/2718>
Co-authored-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
The first frames are typically received and decoded with more delay than
the others, causing a wrong slope estimation on start.
To compensate, assume an initial slope of 1, then progressively use the
estimated slope.
To minimize latency (at the cost of jitter), scrcpy always displays a
frame as soon as it available, without waiting.
However, when recording (--record), it still writes the captured
timestamps to the output file, so that the recorded file can be played
correctly without jitter.
Some real-time use cases might benefit from adding a small latency to
compensate for jitter too. For example, few tens of seconds of latency
for live-streaming are not important, but jitter is noticeable.
Therefore, implement a buffering mechanism (disabled by default) to add
a configurable latency delay.
PR #2417 <https://github.com/Genymobile/scrcpy/issues/2417>
Currently, a frame is available to the consumer as soon as it is pushed
by the producer (which can detect if the previous frame is skipped).
Notify the new frames (and frame skipped) via callbacks instead.
This paves the way to add (optional) buffering, which will introduce a
delay between the time when the frame is produced and the time it is
available to be consumed.
The current video buffer only stores one pending frame.
In order to add a new buffering feature, move this part to a separate
"frame buffer". Keep the video_buffer, which currently delegates all its
calls to the frame_buffer.
To fix a data race, commit 5caeab5f6d
called video_buffer_push() and video_buffer_consume() under the
v4l2_sink lock.
Instead, use the previous_skipped indication (initialized with video
buffer locked) to lock only for protecting the has_frame flag.
This enables the possibility for the video_buffer to notify new frames
via callbacks without lock inversion issues.
The function sc_cond_timedwait() accepted a parameter representing the
max duration to wait, because it internally uses SDL_CondWaitTimeout().
Instead, accept a deadline, to be consistent with
pthread_cond_timedwait().
The v4l2_sink implementation directly read the internal video_buffer
field "pending_frame_consumed", which is protected by the internal
video_buffer mutex. But this mutex was not locked, so reads were racy.
Lock using the v4l2_sink mutex in addition, and use a separate field to
avoid depending on the video_buffer internal data.
Commit 21d206f360 added mutex assertions.
However, the "locker" variable to trace the locker thread id was read
and written by several threads without any protection, so it was racy.
Reported by TSAN.
The options --no-display and --no-control are independent.
The controller was not initialized when no display was requested,
because it was assumed that no control could occur without display. But
that's not true (anymore): for example, it is possible to pass
--turn-screen-off.
Fixes#2426 <https://github.com/Genymobile/scrcpy/issues/2426>
Mouse motion events were forwarded as soon as any mouse button was
pressed.
Instead, only consider left-click (and also middle-click and right-click
if --forward-all-clicks is enabled).
Change the default push target from /sdcard/ to /sdcard/Download/.
Pushing to the root of /sdcard/ is not very convenient, many apps do not
expose its content directly.
It can still be changed by --push-target.
PR #2384 <https://github.com/Genymobile/scrcpy/pull/2384>
When removing the black borders (by double-clicking on them, or by
pressing MOD+w), the window is resized to fit the device screen, but its
top-left position was left unchanged.
Instead, move the window so that the new window area is at the center of
the old window area.
Refs #2387 <https://github.com/Genymobile/scrcpy/issues/2387>
It should not be necessary, since screen_render() is called just after
on SDL_WINDOWEVENT_EXPOSED, but in practice the window content might not
be correctly displayed on restored if a rotation occurred while
minimized.
Note that calling screen_render() twice in a row on
SDL_WINDOWEVENT_EXPOSED also "fixes" the issue.
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
From FFmpeg/doc/APIchanges:
2021-03-17 - f7db77bd87 - lavc 58.133.100 - codec.h
Deprecated av_init_packet(). Once removed, sizeof(AVPacket) will
no longer be a part of the public ABI.
Remove the has_pending boolean, which can be replaced by:
stream->pending != NULL
Refs #2302 <https://github.com/Genymobile/scrcpy/issues/2302>
The input manager was partially initialized statically, but a call to
input_manager_init() was needed anyway, so initialize all the fields
from the "constructor".
This is consistent with the initialization of the other structs.
The frame can be unref immediately after it is pushed to the frame
sinks.
It was not really a memory leak because the frame was unref every time
by avcodec_receive_frame() (and freed on close), but a reference was
unnecessarily kept for too long.
Add a new mode to the --lock-video-orientation option, to lock the
initial orientation of the device.
This avoids to pass an explicit value (0, 1, 2 or 3) and think about
which is the right one.
The screen may not be destroyed immediately on close to avoid undefined
behavior, because it may still receive events from the decoder.
But the visual window must still be closed immediately.
The destruction order is important, but tricky, because the screen is
open/close by the decoder, but destroyed by scrcpy.c on the main thread.
Add assertions to guarantee that the screen is not destroyed before
being closed.
The video buffer is now an internal detail of the screen component.
Since the screen is plugged to the decoder via the frame sink trait, the
decoder does not access to the video buffer anymore.
The fact that the recorder uses a separate thread is an internal detail,
so the functions _start(), _stop() and _join() should not be exposed.
Instead, start the thread on _open() and _stop()+_join() on close().
This paves the way to expose the recorder as a packet sink trait.
The video buffer took ownership of the producer frame (so that it could
swap frames quickly).
In order to support multiple sinks plugged to the decoder, the decoded
frame must not be consumed by the display video buffer.
Therefore, move the producer and consumer frames out of the video
buffer, and use FFmpeg AVFrame refcounting to share ownership while
avoiding copies.
This flag forced the decoder to wait for the previous frame to be
consumed by the display.
It was initially implemented as a compilation flag for testing, not
intended to be exposed at runtime. But to remove ifdefs and to allow
users to test this flag easily, it had finally been exposed by commit
ebccb9f6cc.
In practice, it turned out to be useless: it had no practical impact,
and it did not solve or mitigate any performance issues causing frame
skipping.
But that added some complexity to the codebase: it required an
additional condition variable, and made video buffer calls possibly
blocking, which in turn required code to interrupt it on exit.
To prepare support for multiple sinks plugged to the decoder (display
and v4l2 for example), the blocking call used for pacing the decoder
output becomes unacceptable, so just remove this useless "feature".
Double-click on extra mouse button to open the settings panel (a
single-click opens the notification panel).
This is consistent with the keyboard shortcut MOD+n+n.
PR #2264 <https://github.com/Genymobile/scrcpy/pull/2264>
Signed-off-by: Romain Vimont <rom@rom1v.com>
The collapsing action collapses any panels.
By the way, the Android method is named collapsePanels().
PR #2260 <https://github.com/Genymobile/scrcpy/pull/2260>
Signed-off-by: Romain Vimont <rom@rom1v.com>
The shortcut "back on screen on" is a bit special: the control is
requested by the client, but the actual event injection (POWER or BACK)
is determined on the device.
To properly inject DOWN and UP events for BACK, transmit the action as
a control parameter.
If the screen is off:
- on DOWN, inject POWER (DOWN and UP) (wake up the device immediately)
- on UP, do nothing
If the screen is on:
- on DOWN, inject BACK DOWN
- on UP, inject BACK UP
A corner case is when the screen turns off between the DOWN and UP
event. In that case, a BACK UP event will be injected, so it's harmless.
As a consequence of this change, the BACK button is now handled by
Android on mouse released. This is consistent with the keyboard shortcut
(Mod+b) behavior.
PR #2259 <https://github.com/Genymobile/scrcpy/pull/2259>
Refs #2258 <https://github.com/Genymobile/scrcpy/pull/2258>
The screen receives callbacks from the decoder, fed by the stream.
The decoder is run from the stream thread, so waiting for the end of
stream is sufficient to avoid possible use-after-destroy.
When --no-display was passed, screen_destroy() was called while
screen_init() was never called.
In practice, it did not crash because it just freed NULL pointers, but
it was still incorrect.
A skipped frame is detected when the producer offers a frame while the
current pending frame has not been consumed.
However, the producer (in practice the decoder) is not interested in the
fact that a frame has been skipped, only the consumer (the renderer) is.
Therefore, notify frame skip via a consumer callback. This allows to
manage the skipped and rendered frames count at the same place, and
remove fps_counter from decoder.
As soon as the stream is started, the video buffer could notify a new
frame available.
In order to pass this event to the screen without race condition, the
screen must be initialized before the screen is started.
Video buffer is a tool between a frame producer and a frame consumer.
For now, it is used between a decoder and a renderer, but in the future
another instance might be used to swscale decoded frames.
It makes sense to extract default values for bitrate and port range
(which are arbitrary and might be changed in the future).
However, the default values for "max size" and "lock video orientation"
are naturally unlimited/unlocked, and will never be changed. Extracting
these options just added complexity for no benefit, so hardcode them.
After the struct screen is initialized, the window, the renderer and the
texture are necessarily valid, so there is no need to check in
screen_destroy().
There were only two frames simultaneously:
- one used by the decoder;
- one used by the renderer.
When the decoder finished decoding a frame, it swapped it with the
rendering frame.
Adding a third frame provides several benefits:
- the decoder do not have to wait for the renderer to release the
mutex;
- it simplifies the video_buffer API;
- it makes the rendering frame valid until the next call to
video_buffer_take_rendering_frame(), which will be useful for
swscaling on window resize.
The functions SDL_malloc(), SDL_free() and SDL_strdup() were used only
because strdup() was not available everywhere.
Now that it is available, use the native version of these functions.
Small unsigned integers promote to signed int. As a consequence, if v is
a uint8_t, then (v << 24) yields an int, so the left shift is undefined
if the MSB is 1.
Cast to uint32_t to yield an unsigned value.
Reported by USAN (meson x -Db_sanitize=undefined):
runtime error: left shift of 255 by 24 places cannot be represented
in type 'int'
The current process could be waited both by run_file_handler() and
file_handler_stop().
To avoid the race condition, wait the process without closing, then
close with mutex locked.
There were two versions: process_wait() and process_wait_noclose().
Expose a single version with a flag (it was already implemented that way
internally).
The function process_wait() returned a bool (true if the process
terminated successfully) and provided the exit code via an output
parameter exit_code.
But the returned value was always equivalent to exit_code == 0, so just
return the exit code instead.
The size, point and position structs were defined in common.h. Move them
to coords.h so that common.h could be used for generic code to be
included in all source files.
The header libavformat/version.h was included, but not
libavcodec/version.h.
As a consequence, the LIBAVCODEC_VERSION_INT definition depended on the
caller includes.
On Linux, waitpid() both waits for the process to terminate and reaps it
(closes its handle). On Windows, these actions are separated into
WaitForSingleObject() and CloseHandle().
Expose these actions separately, so that it is possible to send a signal
to a process while waiting for its termination without race condition.
This allows to wait for server termination normally, but kill the
process without race condition if it is not terminated after some delay.
Let the server terminate properly once all the sockets are closed.
If it does not terminate (this can happen if the device is asleep), then
kill it.
Note: since the server process termination is detected by a flag set
after waitpid() returns, there is a small chance that the process
terminates (and the PID assigned to a new process) before the flag is
set but before the kill() call. This race condition already existed
before this commit.
Fixes#1992 <https://github.com/Genymobile/scrcpy/issues/1992>
TerminateProcess() is "equivalent" to kill(), while
WaitForSingleObject() is "equivalent" to waitpid(), so the handle must
be closed after WaitForSingleObject().
On Windows, scrcpy paused on error before exiting to give the user a
chance to see the user message.
This was a hack and causes issues when using scrcpy from batch scripts.
Disable this pause from the scrcpy binary, and provide a batch wrapper
(scrcpy-console.bat) to pause on error.
Fixes#1875 <https://github.com/Genymobile/scrcpy/issues/1875>
Use "%Iu" on Windows. This fixes the following warning:
../app/src/sys/win/command.c:17:14: warning: unknown conversion type character ‘l’ in format [-Wformat=]
17 | LOGE("Command too long (%" PRIsizet " chars)", len - 1);
A new "repeat" field has been added by
3c1ed5d86c, but it was not initialized in
every code path.
As a consequence, keycodes generated by shortcuts were sent with an
undetermined value, breaking some shortcuts (especially HOME) randomly.
Fixes#1643 <https://github.com/Genymobile/scrcpy/issues/1643>
This avoids to pass specific options values individually. Since these
function are static (internal to the file), this is not a problem to
make them depend on scrcpy_options.
Refs #1623 <https://github.com/Genymobile/scrcpy/pull/1623>
Signed-off-by: Romain Vimont <rom@rom1v.com>
Send COPY and CUT on MOD+c and MOD+x (only supported for Android >= 7).
The shortcuts Ctrl+c and Ctrl+x should generally also work (even before
Android 7), but the active Android app may use them for other actions
instead.
Do not explicitly set the clipboard text if it already contains the
expected content.
Even if copy-paste loops are avoided by the previous commit, this avoids
to trigger a clipboard change on the computer-side.
Refs #1580 <https://github.com/Genymobile/scrcpy/issues/1580>
Pressing Ctrl+v on the device will typically paste the clipboard
content.
Before sending the key event, synchronize the computer clipboard to the
device clipboard to allow seamless copy-paste.
Now that the scrcpy shortcut modifier is Alt by default (and can be
configured), forward Ctrl to the device.
This allows to trigger Android shortcuts.
Fixes#555 <https://github.com/Genymobile/scrcpy/issues/555>
Pressing Alt+c generates a text event containing "c", so "c" was sent to
the device when --prefer-text was enabled.
Ignore text events when the mod state matches a shortcut modifier.
Remove the Cmd modifier on macOS, which was possible only for some
shortcuts but not all.
This paves the way to make the shortcut modifier customizable.
Touch events were HiDPI-scaled twice:
- once because the position (provided as floats between 0 and 1) were
converted in pixels using the drawable size (not the window size)
- once due to screen_convert_to_frame_coords()
One possible fix could be to compute the position in pixels from the
window size instead, but this would unnecessarily round the event
position to the nearest window coordinates (instead of drawable
coordinates).
Instead, expose two separate functions to convert to frame coordinates
from either window or drawable coordinates.
Fixes#1536 <https://github.com/Genymobile/scrcpy/issues/1536>
Refs #15 <https://github.com/Genymobile/scrcpy/issues/15>
Refs e40532a376
The header scrcpy.h is intended to be the "public" API. It should not
depend on other internal headers.
Therefore, declare all required structs in this header and adapt
internal code.
The function must return a SDL_LogPriority, but returned an enum
sc_log_level.
(It was harmless because this specific return should never happen, as
asserted.)
This reverts commit 8c8649cfcd.
I cannot reproduce the issue with Ctrl+Shift+o on any device, so in
practice it works, it's too bad to remove the feature for a random bug
on some Android versions on some devices.
Add a command-line option to force "adb forward", without attempting
"adb reverse" first.
This is especially useful for using SSH tunnels without enabling remote
port forwarding.
The verbosity was set either to info (in release mode) or debug (in
debug mode).
Add a command-line argument to change it, so that users can enable debug
logs using the release:
scrcpy -Vdebug
The field lock_video_orientation may only take values between -1 and 3
(included). But the compiler may trigger a warning on the sprintf()
call, because its type could represent values which could overflow the
string (like "-128"):
> warning: ‘%i’ directive writing between 1 and 4 bytes into a region of
> size 3 [-Wformat-overflow=]
Increase the buffer size to remove the warning.
Trilinear filtering can currently only be enabled for OpenGL renderers.
Do not print a warning if the renderer is not OpenGL, as it can confuses
users, while nothing is wrong.
On macOS with renderer "metal", HiDPI scaling may be incorrect on
initialization when several displays are connected.
Resetting the window size fixes the problem.
Refs #15 <https://github.com/Genymobile/scrcpy/issues/15>
Position and scale the content "manually" instead of relying on the
renderer "logical size".
This avoids possible rounding differences between the computed window
size and the content size, causing one row or column of black pixels on
the bottom or on the right.
This also avoids HiDPI scale issues, by computing the scaling manually.
This will also enable to draw items at their expected size on the screen
(unscaled).
Fixes#15 <https://github.com/Genymobile/scrcpy/issues/15>
In maximized state (but not fullscreen), it was possible to resize to
fit the device screen (with Ctrl+x or double-clicking on black borders).
This caused problems on macOS with the "expand to fullscreen" feature,
which behaves like a fullscreen mode but is seen as maximized by SDL.
In that state, resizing to fit causes unexpected results.
To keep the behavior consistent on all platforms, just disable "resize
to fit" when the window is maximized.
On Windows, in maximized+fullscreen state, disabling fullscreen mode
unexpectedly triggers the "restored" then "maximized" events, leaving
the window in a weird state (maximized according to the events, but not
maximized visually).
Moreover, apply_pending_resize() asserts that fullscreen is disabled.
To avoid the issue, if fullscreen is set, just ignore the "restored"
event.
If the content size changes (due to rotation for example) while the
window is maximized or fullscreen, the resize must be applied once
fullscreen and maximized are disabled.
The previous strategy consisted in storing the windowed size, computing
the target size on rotation, and applying it on window restoration. But
tracking the windowed size (while ignoring the non-windowed size) was
tricky, due to unspecified order of SDL events (e.g. size changes can be
notified before "maximized" events), race conditions when reading window
flags, different behaviors on different platforms...
To simplify the whole resize management, store the old content size (the
frame size, possibly rotated) when it changes while the window is
maximized or fullscreen, so that the new optimal size can be computed on
window restoration.
By default, Ctrl+C just kills the process on Windows. This caused
corrupted video files on recording.
Handle Ctrl+C properly to clean up properly.
Fixes#818 <https://github.com/Genymobile/scrcpy/issues/818>
Now that the server can access the Android settings and clean up
properly, handle the "show touches" option from the server.
The initial state is now correctly restored, even on device
disconnection.
The window dimensions are integers, so resizing to fit the content may
not be exact.
When computing the optimal size, it could cause to reduce alternatively
the width and height by few pixels, making the "optimal size" unstable.
To avoid this problem, check if the optimal size is already correct
either by keeping the width or the height.
Move the window-to-frame coordinates conversion from the input manager
to the screen.
This will allow to apply more screen-related transformations without
impacting the input manager.
Some compilers warns on uninitialized value in impossible case:
warning: variable 'result' is used uninitialized whenever switch
default is taken [-Wsometimes-uninitialized]