Compare commits

..

6 Commits

Author SHA1 Message Date
c29ecd0314 Rename --display-buffer to --video-buffer
For consistency with --audio-buffer, rename --display-buffer to
--video-buffer.

Fixes #5403 <https://github.com/Genymobile/scrcpy/issues/5403>
PR #5420 <https://github.com/Genymobile/scrcpy/pull/5420>
2024-10-31 19:57:52 +01:00
d62fa8880e Disable broken options on Android 14
The options --lock-video-orientation and --crop are broken since Android
14. Hopefully, they will be reimplemented differently.

Meanwhile, when running Android >= 14, fail with an error to prevent
incorrect behavior.

Refs #4011 <https://github.com/Genymobile/scrcpy/issues/4011>
Refs #4162 <https://github.com/Genymobile/scrcpy/issues/4162>
PR #5417 <https://github.com/Genymobile/scrcpy/pull/5417>
2024-10-31 19:55:47 +01:00
1f6634ea87 Document adb shell settings commands
Some scrcpy features change Android settings with `adb shell settings`.
Document the commands to execute manually.
2024-10-30 22:23:53 +01:00
58ba00fa06 Adapt "turn screen off" for Android 15
Android 15 introduced an easy way to set the display power:
<fd8b5efc7f%5E!/#F17>

Refs #3927 <https://github.com/Genymobile/scrcpy/issues/3927>
Refs <https://issuetracker.google.com/issues/303565669>
PR #5418 <https://github.com/Genymobile/scrcpy/pull/5418>
2024-10-30 19:38:35 +01:00
569c37cec1 Disable display power for virtual displays
If displayId == Device.DISPLAY_ID_NONE, then the display is virtual: its
power mode cannot be changed.

PR #5418 <https://github.com/Genymobile/scrcpy/pull/5418>
2024-10-30 19:38:07 +01:00
58a0fbbf2e Refactor display power mode
Accept a single boolean "on" rather than a "mode" (which, in practice,
could only take 2 values: NORMAL and OFF).

Also rename "screen power mode" to "display power".

PR #5418 <https://github.com/Genymobile/scrcpy/pull/5418>
2024-10-30 19:38:04 +01:00
17 changed files with 111 additions and 36 deletions

View File

@ -20,7 +20,6 @@ _scrcpy() {
--crop=
-d --select-usb
--disable-screensaver
--display-buffer=
--display-id=
--display-orientation=
-e --select-tcpip
@ -90,6 +89,7 @@ _scrcpy() {
--v4l2-sink=
-v --version
-V --verbosity=
--video-buffer=
--video-codec=
--video-codec-options=
--video-encoder=
@ -191,7 +191,6 @@ _scrcpy() {
|--camera-size \
|--crop \
|--display-id \
|--display-buffer \
|--max-fps \
|-m|--max-size \
|-p|--port \
@ -201,6 +200,7 @@ _scrcpy() {
|--tunnel-port \
|--v4l2-buffer \
|--v4l2-sink \
|--video-buffer \
|--video-codec-options \
|--video-encoder \
|--tcpip \

View File

@ -27,7 +27,6 @@ arguments=(
'--crop=[\[width\:height\:x\:y\] Crop the device screen on the server]'
{-d,--select-usb}'[Use USB device]'
'--disable-screensaver[Disable screensaver while scrcpy is running]'
'--display-buffer=[Add a buffering delay \(in milliseconds\) before displaying]'
'--display-id=[Specify the display id to mirror]'
'--display-orientation=[Set the initial display orientation]:orientation values:(0 90 180 270 flip0 flip90 flip180 flip270)'
{-e,--select-tcpip}'[Use TCP/IP device]'
@ -92,6 +91,7 @@ arguments=(
'--v4l2-sink=[\[\/dev\/videoN\] Output to v4l2loopback device]'
{-v,--version}'[Print the version of scrcpy]'
{-V,--verbosity=}'[Set the log level]:verbosity:(verbose debug info warn error)'
'--video-buffer=[Add a buffering delay \(in milliseconds\) before displaying video frames]'
'--video-codec=[Select the video codec]:codec:(h264 h265 av1)'
'--video-codec-options=[Set a list of comma-separated key\:type=value options for the device video encoder]'
'--video-encoder=[Use a specific MediaCodec video encoder]'

View File

@ -139,12 +139,6 @@ Also see \fB\-e\fR (\fB\-\-select\-tcpip\fR).
.BI "\-\-disable\-screensaver"
Disable screensaver while scrcpy is running.
.TP
.BI "\-\-display\-buffer " ms
Add a buffering delay (in milliseconds) before displaying. This increases latency to compensate for jitter.
Default is 0 (no buffering).
.TP
.BI "\-\-display\-id " id
Specify the device display id to mirror.
@ -560,7 +554,15 @@ It requires to lock the video orientation (see \fB\-\-lock\-video\-orientation\f
.BI "\-\-v4l2-buffer " ms
Add a buffering delay (in milliseconds) before pushing frames. This increases latency to compensate for jitter.
This option is similar to \fB\-\-display\-buffer\fR, but specific to V4L2 sink.
This option is similar to \fB\-\-video\-buffer\fR, but specific to V4L2 sink.
Default is 0 (no buffering).
.TP
.BI "\-\-video\-buffer " ms
Add a buffering delay (in milliseconds) before displaying video frames.
This increases latency to compensate for jitter.
Default is 0 (no buffering).

View File

@ -50,6 +50,7 @@ enum {
OPT_POWER_OFF_ON_CLOSE,
OPT_V4L2_SINK,
OPT_DISPLAY_BUFFER,
OPT_VIDEO_BUFFER,
OPT_V4L2_BUFFER,
OPT_TUNNEL_HOST,
OPT_TUNNEL_PORT,
@ -321,12 +322,10 @@ static const struct sc_option options[] = {
.argdesc = "id",
},
{
// deprecated
.longopt_id = OPT_DISPLAY_BUFFER,
.longopt = "display-buffer",
.argdesc = "ms",
.text = "Add a buffering delay (in milliseconds) before displaying. "
"This increases latency to compensate for jitter.\n"
"Default is 0 (no buffering).",
},
{
.longopt_id = OPT_DISPLAY_ID,
@ -898,11 +897,20 @@ static const struct sc_option options[] = {
.argdesc = "ms",
.text = "Add a buffering delay (in milliseconds) before pushing "
"frames. This increases latency to compensate for jitter.\n"
"This option is similar to --display-buffer, but specific to "
"This option is similar to --video-buffer, but specific to "
"V4L2 sink.\n"
"Default is 0 (no buffering).\n"
"This option is only available on Linux.",
},
{
.longopt_id = OPT_VIDEO_BUFFER,
.longopt = "video-buffer",
.argdesc = "ms",
.text = "Add a buffering delay (in milliseconds) before displaying "
"video frames.\n"
"This increases latency to compensate for jitter.\n"
"Default is 0 (no buffering).",
},
{
.longopt_id = OPT_VIDEO_CODEC,
.longopt = "video-codec",
@ -2549,7 +2557,11 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->power_off_on_close = true;
break;
case OPT_DISPLAY_BUFFER:
if (!parse_buffering_time(optarg, &opts->display_buffer)) {
LOGW("--display-buffer is deprecated, use --video-buffer "
"instead.");
// fall through
case OPT_VIDEO_BUFFER:
if (!parse_buffering_time(optarg, &opts->video_buffer)) {
return false;
}
break;
@ -2812,7 +2824,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
LOGI("Video orientation is locked for v4l2 sink. "
"See --lock-video-orientation.");
opts->lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_INITIAL;
opts->lock_video_orientation =
SC_LOCK_VIDEO_ORIENTATION_INITIAL_AUTO;
}
// V4L2 could not handle size change.

View File

@ -58,7 +58,7 @@ const struct scrcpy_options scrcpy_options_default = {
.window_width = 0,
.window_height = 0,
.display_id = 0,
.display_buffer = 0,
.video_buffer = 0,
.audio_buffer = -1, // depends on the audio format,
.audio_output_buffer = SC_TICK_FROM_MS(5),
.time_limit = 0,

View File

@ -134,6 +134,8 @@ enum sc_lock_video_orientation {
SC_LOCK_VIDEO_ORIENTATION_UNLOCKED = -1,
// lock the current orientation when scrcpy starts
SC_LOCK_VIDEO_ORIENTATION_INITIAL = -2,
// like SC_LOCK_VIDEO_ORIENTATION_INITIAL, but set automatically
SC_LOCK_VIDEO_ORIENTATION_INITIAL_AUTO = -3,
SC_LOCK_VIDEO_ORIENTATION_0 = 0,
SC_LOCK_VIDEO_ORIENTATION_90 = 3,
SC_LOCK_VIDEO_ORIENTATION_180 = 2,
@ -259,7 +261,7 @@ struct scrcpy_options {
uint16_t window_width;
uint16_t window_height;
uint32_t display_id;
sc_tick display_buffer;
sc_tick video_buffer;
sc_tick audio_buffer;
sc_tick audio_output_buffer;
sc_tick time_limit;

View File

@ -53,7 +53,7 @@ struct scrcpy {
struct sc_decoder video_decoder;
struct sc_decoder audio_decoder;
struct sc_recorder recorder;
struct sc_delay_buffer display_buffer;
struct sc_delay_buffer video_buffer;
#ifdef HAVE_V4L2
struct sc_v4l2_sink v4l2_sink;
struct sc_delay_buffer v4l2_buffer;
@ -815,11 +815,11 @@ aoa_complete:
if (options->video_playback) {
struct sc_frame_source *src = &s->video_decoder.frame_source;
if (options->display_buffer) {
sc_delay_buffer_init(&s->display_buffer,
options->display_buffer, true);
sc_frame_source_add_sink(src, &s->display_buffer.frame_sink);
src = &s->display_buffer.frame_source;
if (options->video_buffer) {
sc_delay_buffer_init(&s->video_buffer,
options->video_buffer, true);
sc_frame_source_add_sink(src, &s->video_buffer.frame_sink);
src = &s->video_buffer.frame_source;
}
sc_frame_source_add_sink(src, &s->screen.frame_sink);

View File

@ -170,7 +170,7 @@ latency (for both [video](video.md#buffering) and audio) might be preferable to
avoid glitches and smooth the playback:
```
scrcpy --display-buffer=200 --audio-buffer=200
scrcpy --video-buffer=200 --audio-buffer=200
```
It is also possible to configure another audio buffer (the audio output buffer),

View File

@ -21,9 +21,9 @@ the client and on the server.
If video is enabled, then the server sends a raw video stream (H.264 by default)
of the device screen, with some additional headers for each packet. The client
decodes the video frames, and displays them as soon as possible, without
buffering (unless `--display-buffer=delay` is specified) to minimize latency.
The client is not aware of the device rotation (which is handled by the server),
it just knows the dimensions of the video frames it receives.
buffering (unless `--video-buffer=delay` is specified) to minimize latency. The
client is not aware of the device rotation (which is handled by the server), it
just knows the dimensions of the video frames it receives.
Similarly, if audio is enabled, then the server sends a raw audio stream (OPUS
by default) of the device audio output (or the microphone if

View File

@ -18,6 +18,21 @@ The initial state is restored when _scrcpy_ is closed.
If the device is not plugged in (i.e. only connected over TCP/IP),
`--stay-awake` has no effect (this is the Android behavior).
This changes the value of [`stay_on_while_plugged_in`], setting which can be
changed manually:
[`stay_on_while_plugged_in`]: https://developer.android.com/reference/android/provider/Settings.Global#STAY_ON_WHILE_PLUGGED_IN
```bash
# get the current show_touches value
adb shell settings get global stay_on_while_plugged_in
# enable for AC/USB/wireless chargers
adb shell settings put global stay_on_while_plugged_in 7
# disable
adb shell settings put global stay_on_while_plugged_in 0
```
## Turn screen off
@ -46,6 +61,15 @@ scrcpy --turn-screen-off --stay-awake
scrcpy -Sw # short version
```
Since Android 15, it is possible to change this setting manually:
```
# turn screen off (0 for main display)
adb shell cmd display power-off 0
# turn screen on
adb shell cmd display power-on 0
```
## Show touches
@ -62,6 +86,16 @@ scrcpy -t # short version
Note that it only shows _physical_ touches (by a finger on the device).
It is possible to change this setting manually:
```bash
# get the current show_touches value
adb shell settings get system show_touches
# enable show_touches
adb shell settings put system show_touches 1
# disable show_touches
adb shell settings put system show_touches 0
```
## Power off on close

View File

@ -189,15 +189,15 @@ The configuration is available independently for the display,
[v4l2 sinks](video.md#video4linux) and [audio](audio.md#buffering) playback.
```bash
scrcpy --display-buffer=50 # add 50ms buffering for display
scrcpy --v4l2-buffer=300 # add 300ms buffering for v4l2 sink
scrcpy --video-buffer=50 # add 50ms buffering for video playback
scrcpy --audio-buffer=200 # set 200ms buffering for audio playback
scrcpy --v4l2-buffer=300 # add 300ms buffering for v4l2 sink
```
They can be applied simultaneously:
```bash
scrcpy --display-buffer=50 --v4l2-buffer=300
scrcpy --video-buffer=50 --v4l2-buffer=300
```

View File

@ -2,6 +2,7 @@ package com.genymobile.scrcpy;
import com.genymobile.scrcpy.audio.AudioCodec;
import com.genymobile.scrcpy.audio.AudioSource;
import com.genymobile.scrcpy.device.Device;
import com.genymobile.scrcpy.device.NewDisplay;
import com.genymobile.scrcpy.device.Size;
import com.genymobile.scrcpy.util.CodecOption;
@ -31,7 +32,7 @@ public class Options {
private int videoBitRate = 8000000;
private int audioBitRate = 128000;
private float maxFps;
private int lockVideoOrientation = -1;
private int lockVideoOrientation = Device.LOCK_VIDEO_ORIENTATION_UNLOCKED;
private boolean tunnelForward;
private Rect crop;
private boolean control = true;
@ -253,6 +254,10 @@ public class Options {
return sendCodecMeta;
}
public void resetLockVideoOrientation() {
this.lockVideoOrientation = Device.LOCK_VIDEO_ORIENTATION_UNLOCKED;
}
@SuppressWarnings("MethodLength")
public static Options parse(String... args) {
if (args.length < 1) {

View File

@ -132,6 +132,23 @@ public final class Server {
throw new ConfigurationException("New virtual display is not supported");
}
if (Build.VERSION.SDK_INT >= AndroidVersions.API_34_ANDROID_14) {
int lockVideoOrientation = options.getLockVideoOrientation();
if (lockVideoOrientation != Device.LOCK_VIDEO_ORIENTATION_UNLOCKED) {
if (lockVideoOrientation != Device.LOCK_VIDEO_ORIENTATION_INITIAL_AUTO) {
Ln.e("--lock-video-orientation is broken on Android >= 14: <https://github.com/Genymobile/scrcpy/issues/4011>");
throw new ConfigurationException("--lock-video-orientation is broken on Android >= 14");
} else {
// If the flag has been set automatically (because v4l2 sink is enabled), do not fail
Ln.w("--lock-video-orientation is ignored on Android >= 14: <https://github.com/Genymobile/scrcpy/issues/4011>");
}
}
if (options.getCrop() != null) {
Ln.e("--crop is broken on Android >= 14: <https://github.com/Genymobile/scrcpy/issues/4162>");
throw new ConfigurationException("Crop is not broken on Android >= 14");
}
}
CleanUp cleanUp = null;
Thread initThread = null;

View File

@ -273,8 +273,8 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
case ControlMessage.TYPE_SET_DISPLAY_POWER:
if (supportsInputEvents && displayId != Device.DISPLAY_ID_NONE) {
boolean on = msg.getOn();
boolean setPowerModeOk = Device.setDisplayPower(displayId, on);
if (setPowerModeOk) {
boolean setDisplayPowerOk = Device.setDisplayPower(displayId, on);
if (setDisplayPowerOk) {
keepDisplayPowerOff = !on;
Ln.i("Device display turned " + (on ? "on" : "off"));
if (cleanUp != null) {

View File

@ -42,6 +42,8 @@ public final class Device {
public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1;
public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2;
// like SC_LOCK_VIDEO_ORIENTATION_INITIAL, but set automatically
public static final int LOCK_VIDEO_ORIENTATION_INITIAL_AUTO = -3;
private Device() {
// not instantiable

View File

@ -64,7 +64,7 @@ public final class ScreenInfo {
}
public static ScreenInfo computeScreenInfo(int rotation, Size deviceSize, Rect crop, int maxSize, int lockedVideoOrientation) {
if (lockedVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL) {
if (lockedVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL || lockedVideoOrientation == Device.LOCK_VIDEO_ORIENTATION_INITIAL_AUTO) {
// The user requested to lock the video orientation to the current orientation
lockedVideoOrientation = rotation;
}

View File

@ -283,7 +283,7 @@ public class ControlMessageReaderTest {
}
@Test
public void testParseSetScreenPowerMode() throws IOException {
public void testParseSetDisplayPower() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_DISPLAY_POWER);