## File: README.md

> [!WARNING]
> **This GitHub repo (<https://github.com/Genymobile/scrcpy>) is the only official
source for the project. Do not download releases from random websites, even if
their name contains `scrcpy`.**

# scrcpy (v4.1)



_pronounced "**scr**een **c**o**py**"_

This application mirrors Android devices (video and audio) connected via USB or
[TCP/IP](doc/connection.md#tcpip-wireless) and allows control using the
computer's keyboard and mouse. It does not require _root_ access or an app
installed on the device. It works on _Linux_, _Windows_, and _macOS_.

[](doc/linux.md)&nbsp;
[](doc/windows.md)&nbsp;
[](doc/macos.md)&nbsp;



It focuses on:

 - **lightness**: native, displays only the device screen
 - **performance**: 30~120fps, depending on the device
 - **quality**: 1920×1080 or above
 - **low latency**: [35~70ms][lowlatency]
 - **low startup time**: ~1 second to display the first image
 - **non-intrusiveness**: nothing is left installed on the Android device
 - **user benefits**: no account, no ads, no internet required
 - **freedom**: free and open source software

[lowlatency]: https://github.com/Genymobile/scrcpy/pull/646

Its features include:
 - [audio forwarding](doc/audio.md) (Android 11+)
 - [recording](doc/recording.md)
 - [virtual display](doc/virtual-display.md)
 - mirroring with [Android device screen off](doc/device.md#turn-screen-off)
 - [copy-paste](doc/control.md#copy-paste) in both directions
 - [configurable quality](doc/video.md)
 - [camera mirroring](doc/camera.md) (Android 12+)
 - [mirroring as a webcam (V4L2)](doc/v4l2.md) (Linux-only)
 - physical [keyboard][hid-keyboard] and [mouse][hid-mouse] simulation (HID)
 - [gamepad](doc/gamepad.md) support
 - [OTG mode](doc/otg.md)
 - and more…

[hid-keyboard]: doc/keyboard.md#physical-keyboard-simulation
[hid-mouse]: doc/mouse.md#physical-mouse-simulation

## Prerequisites

The Android device requires at least API 21 (Android 5.0).

[Audio forwarding](doc/audio.md) is supported for API >= 30 (Android 11+).

Make sure you [enabled USB debugging][enable-adb] on your device(s).

[enable-adb]: https://developer.android.com/studio/debug/dev-options#enable

On some devices (especially Xiaomi), you might get the following error:

```
Injecting input events requires the caller (or the source of the instrumentation, if any) to have the INJECT_EVENTS permission.
```

In that case, you need to enable [an additional option][control] `USB debugging
(Security Settings)` (this is an item different from `USB debugging`) to control
it using a keyboard and mouse. Rebooting the device is necessary once this
option is set.

[control]: https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323

Note that USB debugging is not required to run scrcpy in [OTG mode](doc/otg.md).


## Get the app

 - [Linux](doc/linux.md)
 - [Windows](doc/windows.md) (read [how to run](doc/windows.md#run))
 - [macOS](doc/macos.md)


## Must-know tips

 - [Reducing resolution](doc/video.md#size) may greatly improve performance
   (`scrcpy -m1024`)
 - [_Right-click_](doc/mouse.md#mouse-bindings) triggers `BACK`
 - [_Middle-click_](doc/mouse.md#mouse-bindings) triggers `HOME`
 - <kbd>Alt</kbd>+<kbd>f</kbd> toggles [fullscreen](doc/window.md#fullscreen)
 - There are many other [shortcuts](doc/shortcuts.md)


## Usage examples

There are a lot of options, [documented](#user-documentation) in separate pages.
Here are just some common examples.

 - Capture the screen in H.265 (better quality), limit the size to 1920, limit
   the frame rate to 60fps, disable audio, and control the device by simulating
   a physical keyboard:

    ```bash
    scrcpy --video-codec=h265 --max-size=1920 --max-fps=60 --no-audio --keyboard=uhid
    scrcpy --video-codec=h265 -m1920 --max-fps=60 --no-audio -K  # short version
    ```

 - Start VLC in a new virtual display (separate from the device display):

    ```bash
    scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
    ```

 - Start VLC in a new _flex_ display using H.265 with a bitrate of 16 Mbps,
   while keeping the display active so it does not turn off:

    ```bash
    scrcpy --new-display -x --keep-active --start-app=org.videolan.vlc --video-codec=h265 -b16M
    ```

 - Record the device camera in H.265 at 1920x1080 (and microphone) to an MP4
   file:

    ```bash
    scrcpy --video-source=camera --video-codec=h265 --camera-size=1920x1080 --record=file.mp4
    ```

 - Capture the device front camera and expose it as a webcam on the computer (on
   Linux):

    ```bash
    scrcpy --video-source=camera --camera-size=1920x1080 --camera-facing=front --v4l2-sink=/dev/video2 --no-playback
    ```

 - Control the device without mirroring by simulating a physical keyboard and
   mouse (USB debugging not required):

    ```bash
    scrcpy --otg
    ```

 - Control the device using gamepads plugged into the computer:

    ```bash
    scrcpy --gamepad=uhid
    scrcpy -G  # short version
    ```

## User documentation

The application provides a lot of features and configuration options. They are
documented in the following pages:

 - [Connection](doc/connection.md)
 - [Video](doc/video.md)
 - [Audio](doc/audio.md)
 - [Control](doc/control.md)
 - [Keyboard](doc/keyboard.md)
 - [Mouse](doc/mouse.md)
 - [Gamepad](doc/gamepad.md)
 - [Device](doc/device.md)
 - [Window](doc/window.md)
 - [Recording](doc/recording.md)
 - [Virtual display](doc/virtual-display.md)
 - [Tunnels](doc/tunnels.md)
 - [OTG](doc/otg.md)
 - [Camera](doc/camera.md)
 - [Video4Linux](doc/v4l2.md)
 - [Shortcuts](doc/shortcuts.md)


## Resources

 - [FAQ](FAQ.md)
 - [Translations][wiki] (not necessarily up to date)
 - [Build instructions](doc/build.md)
 - [Developers](doc/develop.md)
 - [Verify release signatures](doc/verify-release.md)

[wiki]: https://github.com/Genymobile/scrcpy/wiki


## Articles

- [Introducing scrcpy][article-intro]
- [Scrcpy now works wirelessly][article-tcpip]
- [Scrcpy 2.0, with audio][article-scrcpy2]

[article-intro]: https://blog.rom1v.com/2018/03/introducing-scrcpy/
[article-tcpip]: https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
[article-scrcpy2]: https://blog.rom1v.com/2023/03/scrcpy-2-0-with-audio/

## Contact

You can open an [issue] for bug reports, feature requests or general questions.

For bug reports, please read the [FAQ](FAQ.md) first, you might find a solution
to your problem immediately.

[issue]: https://github.com/Genymobile/scrcpy/issues

You can also use:

 - Reddit: [`r/scrcpy`](https://www.reddit.com/r/scrcpy)
 - BlueSky: [`@scrcpy.bsky.social`](https://bsky.app/profile/scrcpy.bsky.social)
 - Twitter: [`@scrcpy_app`](https://twitter.com/scrcpy_app)


## Donate

I'm [@rom1v](https://github.com/rom1v), the author and maintainer of _scrcpy_.

If you appreciate this application, you can [support my open source
work][donate]:
 - [GitHub Sponsors](https://github.com/sponsors/rom1v)
 - [Liberapay](https://liberapay.com/rom1v/)
 - [PayPal](https://paypal.me/rom2v)

[donate]: https://blog.rom1v.com/about/#support-my-open-source-work

## License

    Copyright (C) 2018 Genymobile
    Copyright (C) 2018-2026 Romain Vimont

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

---

## File: doc/audio.md

# Audio

Audio forwarding is supported for devices with Android 11 or higher, and it is
enabled by default:

 - For **Android 12 or newer**, it works out-of-the-box.
 - For **Android 11**, you'll need to ensure that the device screen is unlocked
   when starting scrcpy. A fake popup will briefly appear to make the system
   think that the shell app is in the foreground. Without this, audio capture
   will fail.
 - For **Android 10 or earlier**, audio cannot be captured and is automatically
   disabled.

If audio capture fails, then mirroring continues with video only (since audio is
enabled by default, it is not acceptable to make scrcpy fail if it is not
available), unless `--require-audio` is set.


## No audio

To disable audio:

```bash
scrcpy --no-audio
```

To disable only the audio playback, see [no playback](video.md#no-playback).

## Audio only

To play audio only, disable video and control:

```bash
scrcpy --no-video --no-control
```

To play audio without a window:

```bash
# --no-video and --no-control are implied by --no-window
scrcpy --no-window
# interrupt with Ctrl+C
```

Without video, the audio latency is typically not critical, so it might be
interesting to add [buffering](#buffering) to minimize glitches:

```bash
scrcpy --no-video --audio-buffer=200
```

## Source

By default, the device audio output is forwarded.

It is possible to capture the device microphone instead:

```bash
scrcpy --audio-source=mic
```

For example, to use the device as a dictaphone and record a capture directly on
the computer:

```bash
scrcpy --audio-source=mic --no-video --no-playback --record=file.opus
```

Many sources are available:

 - `output` (default): forwards the whole audio output, and disables playback on the device (mapped to [`REMOTE_SUBMIX`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#REMOTE_SUBMIX)).
 - `playback`: captures the audio playback (Android apps can opt-out, so the whole output is not necessarily captured).
 - `mic`: captures the microphone (mapped to [`MIC`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#MIC)).
 - `mic-unprocessed`: captures the microphone unprocessed (raw) sound (mapped to [`UNPROCESSED`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#UNPROCESSED)).
 - `mic-camcorder`: captures the microphone tuned for video recording, with the same orientation as the camera if available (mapped to [`CAMCORDER`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#CAMCORDER)).
 - `mic-voice-recognition`: captures the microphone tuned for voice recognition (mapped to [`VOICE_RECOGNITION`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_RECOGNITION)).
 - `mic-voice-communication`: captures the microphone tuned for voice communications (it will for instance take advantage of echo cancellation or automatic gain control if available) (mapped to [`VOICE_COMMUNICATION`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_COMMUNICATION)).
 - `voice-call`: captures voice call (mapped to [`VOICE_CALL`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_CALL)).
 - `voice-call-uplink`: captures voice call uplink only (mapped to [`VOICE_UPLINK`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_UPLINK)).
 - `voice-call-downlink`: captures voice call downlink only (mapped to [`VOICE_DOWNLINK`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_DOWNLINK)).
 - `voice-performance`: captures audio meant to be processed for live performance (karaoke), includes both the microphone and the device playback (mapped to [`VOICE_PERFORMANCE`](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_PERFORMANCE)).

### Duplication

An alternative device audio capture method is also available (only for Android
13 and above):

```bash
scrcpy --audio-source=playback
```

This audio source supports keeping the audio playing on the device while
mirroring, with `--audio-dup`:

```bash
scrcpy --audio-source=playback --audio-dup
# or simply:
scrcpy --audio-dup  # --audio-source=playback is implied
```

However, it requires Android 13, and Android apps can opt-out (so they are not
captured).


See [#4380](https://github.com/Genymobile/scrcpy/issues/4380).


## Codec

The audio codec can be selected. The possible values are `opus` (default),
`aac`, `flac` and `raw` (uncompressed PCM 16-bit LE):

```bash
scrcpy --audio-codec=opus  # default
scrcpy --audio-codec=aac
scrcpy --audio-codec=flac
scrcpy --audio-codec=raw
```

In particular, if you get the following error:

> Failed to initialize audio/opus, error 0xfffffffe

then your device has no Opus encoder: try `scrcpy --audio-codec=aac`.

For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--audio-codec-options` in the manpage or in `scrcpy --help`.

For example, to change the [FLAC compression level]:

```bash
scrcpy --audio-codec=flac --audio-codec-options=flac-compression-level=8
```

[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
[FLAC compression level]: https://developer.android.com/reference/android/media/MediaFormat#KEY_FLAC_COMPRESSION_LEVEL


## Encoder

Several encoders may be available on the device. They can be listed by:

```bash
scrcpy --list-encoders
```

To select a specific encoder:

```bash
scrcpy --audio-codec=opus --audio-encoder='c2.android.opus.encoder'
```


## Bit rate

The default audio bit rate is 128Kbps. To change it:

```bash
scrcpy --audio-bit-rate=64K
scrcpy --audio-bit-rate=64000  # equivalent
```

_This parameter does not apply to RAW audio codec (`--audio-codec=raw`)._


## Buffering

Audio buffering is unavoidable. It must be kept small enough so that the latency
is acceptable, but large enough to minimize buffer underrun (causing audio
glitches).

The default buffer size is set to 50ms. It can be adjusted:

```bash
scrcpy --audio-buffer=40   # smaller than default
scrcpy --audio-buffer=100  # higher than default
```

Note that this option changes the _target_ buffering. It is possible that this
target buffering might not be reached (on frequent buffer underflow typically).

If you don't interact with the device (to watch a video for example), a higher
latency (for both [video](video.md#buffering) and audio) might be preferable to
avoid glitches and smooth the playback:

```bash
scrcpy --video-buffer=200 --audio-buffer=200
```

It is also possible to configure another audio buffer (the audio output buffer),
by default set to 10ms. Do not change this setting unless you have a good reason
(see [robotic and glitchy sound][#3793]). For instance:

```bash
scrcpy --audio-output-buffer=5
```

[#3793]: https://github.com/Genymobile/scrcpy/issues/3793

---

## File: doc/build.md

# Build scrcpy

Here are the instructions to build _scrcpy_ (client and server).

If you just want to build and install the latest release, follow the simplified
process described in [doc/linux.md](linux.md).

## Branches

There are two main branches:
 - `master`: contains the latest release. It is the home page of the project on
   GitHub.
 - `dev`: the current development branch. Every commit present in `dev` will be
   in the next release.

If you want to contribute code, please base your commits on the latest `dev`
branch.


## Requirements

You need [adb]. It is available in the [Android SDK platform
tools][platform-tools], or packaged in your distribution (`adb`).

On Windows, download the [platform-tools][platform-tools-windows] and extract
the following files to a directory accessible from your `PATH`:
 - `adb.exe`
 - `AdbWinApi.dll`
 - `AdbWinUsbApi.dll`

It is also available in scrcpy releases.

The client requires [FFmpeg] and [SDL]. Just follow the instructions.

[adb]: https://developer.android.com/studio/command-line/adb.html
[platform-tools]: https://developer.android.com/studio/releases/platform-tools.html
[platform-tools-windows]: https://dl.google.com/android/repository/platform-tools-latest-windows.zip
[ffmpeg]: https://en.wikipedia.org/wiki/FFmpeg
[SDL]: https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer



## System-specific steps

### Linux

Install the required packages from your package manager.

#### Debian/Ubuntu

```bash
# runtime dependencies
sudo apt install ffmpeg libsdl3-0 adb libusb-1.0-0

# client build dependencies
sudo apt install gcc git pkg-config meson ninja-build libsdl3-dev \
                 libavcodec-dev libavdevice-dev libavformat-dev libavutil-dev \
                 libswresample-dev libusb-1.0-0-dev libv4l-dev

# server build dependencies
sudo apt install openjdk-17-jdk
```

On old versions (like Ubuntu 16.04), `meson` is too old. In that case, install
it from `pip3`:

```bash
sudo apt install python3-pip
pip3 install meson
```


#### Fedora

```bash
# enable RPM fusion free
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm

# client build dependencies
sudo dnf install SDL3-devel ffms2-devel libusb1-devel libavdevice-free-devel meson gcc make

# server build dependencies
sudo dnf install java-devel
```



### Windows

#### Cross-compile from Linux

This is the preferred method (and the way the release is built).

From _Debian_, install _mingw_:

```bash
sudo apt install mingw-w64 mingw-w64-tools libz-mingw-w64-dev
```

You also need the JDK to build the server:

```bash
sudo apt install openjdk-17-jdk
```

Then generate the releases:

```bash
./release.sh
```

It will generate win32 and win64 releases into `dist/`.


#### In MSYS2

From Windows, you need [MSYS2] to build the project. From an MSYS2 terminal,
install the required packages:

[MSYS2]: http://www.msys2.org/

```bash
# runtime dependencies
pacman -S mingw-w64-x86_64-sdl3 \
          mingw-w64-x86_64-ffmpeg \
          mingw-w64-x86_64-libusb

# client build dependencies
pacman -S mingw-w64-x86_64-make \
          mingw-w64-x86_64-gcc \
          mingw-w64-x86_64-pkg-config \
          mingw-w64-x86_64-meson
```

For a 32 bits version, replace `x86_64` by `i686`:

```bash
# runtime dependencies
pacman -S mingw-w64-i686-sdl3 \
          mingw-w64-i686-ffmpeg \
          mingw-w64-i686-libusb

# client build dependencies
pacman -S mingw-w64-i686-make \
          mingw-w64-i686-gcc \
          mingw-w64-i686-pkg-config \
          mingw-w64-i686-meson
```

Java (>= 7) is not available in MSYS2, so if you plan to build the server,
install it manually and make it available from the `PATH`:

```bash
export PATH="$JAVA_HOME/bin:$PATH"
```

When following the rest of the build instructions below, make sure you use the
MinGW terminal within MSYS2.


### macOS

Install the packages with [Homebrew]:

[Homebrew]: https://brew.sh/

```bash
# runtime dependencies
brew install sdl3 ffmpeg libusb

# client build dependencies
brew install pkg-config meson
```

Additionally, if you want to build the server, install Java 17 from Caskroom, and
make it available from the `PATH`:

```bash
brew install openjdk@17
export JAVA_HOME="$(/usr/libexec/java_home --version 1.17)"
export PATH="$JAVA_HOME/bin:$PATH"
```

### Docker

See [pierlon/scrcpy-docker](https://github.com/pierlon/scrcpy-docker).


## Common steps

**As a non-root user**, clone the project:

```bash
git clone https://github.com/Genymobile/scrcpy
cd scrcpy
```


### Build

You may want to build only the client: the server binary, which will be pushed
to the Android device, does not depend on your system and architecture. In that
case, use the [prebuilt server] (so you will not need Java or the Android SDK).

[prebuilt server]: #option-2-use-prebuilt-server


#### Option 1: Build everything from sources

Install the [Android SDK] (_Android Studio_), and set `ANDROID_SDK_ROOT` to its
directory. For example:

[Android SDK]: https://developer.android.com/studio/index.html

```bash
# Linux
export ANDROID_SDK_ROOT=~/Android/Sdk
# Mac
export ANDROID_SDK_ROOT=~/Library/Android/sdk
# Windows
set ANDROID_SDK_ROOT=%LOCALAPPDATA%\Android\sdk
```

Then, build:

```bash
meson setup x --buildtype=release --strip -Db_lto=true
ninja -Cx  # DO NOT RUN AS ROOT
```

_Note: `ninja` [must][ninja-user] be run as a non-root user (only `ninja
install` must be run as root)._

[ninja-user]: https://github.com/Genymobile/scrcpy/commit/4c49b27e9f6be02b8e63b508b60535426bd0291a


#### Option 2: Use prebuilt server

 - [`scrcpy-server-v4.1`][direct-scrcpy-server]  
   <sub>SHA-256: `deacb991ed2509715160ffdc7907e47b4160eb30d1566217e9047fd5b8850cae`</sub>

[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v4.1/scrcpy-server-v4.1

Download the prebuilt server somewhere, and specify its path during the Meson
configuration:

```bash
meson setup x --buildtype=release --strip -Db_lto=true \
    -Dprebuilt_server=/path/to/scrcpy-server
ninja -Cx  # DO NOT RUN AS ROOT
```

The server only works with a matching client version (this server works with the
`master` branch).


### Run without installing:

```bash
./run x [options]
```


### Install

After a successful build, you can install _scrcpy_ on the system:

```bash
sudo ninja -Cx install    # without sudo on Windows
```

This installs several files:

 - `/usr/local/bin/scrcpy` (main app)
 - `/usr/local/share/scrcpy/scrcpy-server` (server to push to the device)
 - `/usr/local/share/man/man1/scrcpy.1` (manpage)
 - `/usr/local/share/icons/hicolor/256x256/apps/scrcpy.png` (app icon)
 - `/usr/local/share/icons/hicolor/256x256/apps/disconnected.png` (device
   disconnected icon)
 - `/usr/local/share/zsh/site-functions/_scrcpy` (zsh completion)
 - `/usr/local/share/bash-completion/completions/scrcpy` (bash completion)
 - `/usr/local/share/applications/scrcpy.desktop` (app-without-console desktop
   entry file)
 - `/usr/local/share/applications/scrcpy-console.desktop` (app-with-console
   desktop entry file)

You can then run `scrcpy`.


### Uninstall

```bash
sudo ninja -Cx uninstall  # without sudo on Windows
```

---

## File: doc/camera.md

# Camera

Camera mirroring is supported for devices with Android 12 or higher.

To capture the camera instead of the device screen:

```bash
scrcpy --video-source=camera
```

By default, it automatically switches [audio source](audio.md#source) to
microphone (as if `--audio-source=mic` were also passed).

```bash
scrcpy --video-source=display  # default is --audio-source=output
scrcpy --video-source=camera   # default is --audio-source=mic
scrcpy --video-source=display --audio-source=mic    # force display AND microphone
scrcpy --video-source=camera --audio-source=output  # force camera AND device audio output
```

Audio can be disabled:

```bash
# audio not captured at all
scrcpy --video-source=camera --no-audio
scrcpy --video-source=camera --no-audio --record=file.mp4

# audio captured and recorded, but not played
scrcpy --video-source=camera --no-audio-playback --record=file.mp4
```


## List

To list the cameras available (with their declared valid sizes and frame rates):

```bash
scrcpy --list-cameras
scrcpy --list-camera-sizes
```

_Note that the sizes and frame rates are declarative. They are not accurate on
all devices: some of them are declared but not supported, while some others are
not declared but supported._


## Selection

It is possible to pass an explicit camera id (as listed by `--list-cameras`):

```bash
scrcpy --video-source=camera --camera-id=0
```

Alternatively, the camera may be selected automatically:

```bash
scrcpy --video-source=camera                           # use the first camera
scrcpy --video-source=camera --camera-facing=front     # use the first front camera
scrcpy --video-source=camera --camera-facing=back      # use the first back camera
scrcpy --video-source=camera --camera-facing=external  # use the first external camera
```

If `--camera-id` is specified, then `--camera-facing` is forbidden (the id
already determines the camera):

```bash
scrcpy --video-source=camera --camera-id=0 --camera-facing=front  # error
```


### Size selection

It is possible to pass an explicit camera size:

```bash
scrcpy --video-source=camera --camera-size=1920x1080
```

The given size may be listed among the declared valid sizes
(`--list-camera-sizes`), but may also be anything else (some devices support
arbitrary sizes):

```bash
scrcpy --video-source=camera --camera-size=1840x444
```

Alternatively, a declared valid size (among the ones listed by
`list-camera-sizes`) may be selected automatically.

Two constraints are supported:
 - `-m`/`--max-size` (already used for display mirroring), for example `-m1920`;
 - `--camera-ar` to specify an aspect ratio (`<num>:<den>`, `<value>` or
   `sensor`).

Some examples:

```bash
scrcpy --video-source=camera                          # use the greatest width and the greatest associated height
scrcpy --video-source=camera -m1920                   # use the greatest width not above 1920 and the greatest associated height
scrcpy --video-source=camera --camera-ar=4:3          # use the greatest size with an aspect ratio of 4:3 (+/- 10%)
scrcpy --video-source=camera --camera-ar=1.6          # use the greatest size with an aspect ratio of 1.6 (+/- 10%)
scrcpy --video-source=camera --camera-ar=sensor       # use the greatest size with the aspect ratio of the camera sensor (+/- 10%)
scrcpy --video-source=camera -m1920 --camera-ar=16:9  # use the greatest width not above 1920 and the closest to 16:9 aspect ratio
```

If `--camera-size` is specified, then `-m`/`--max-size` and `--camera-ar` are
forbidden (the size is determined by the value given explicitly):

```bash
scrcpy --video-source=camera --camera-size=1920x1080 -m3000  # error
```


## Rotation

To rotate the captured video, use the [video orientation](video.md#orientation)
option:

```bash
scrcpy --video-source=camera --camera-size=1920x1080 --orientation=90
```


## Frame rate

By default, camera is captured at Android's default frame rate (30 fps).

To configure a different frame rate:

```bash
scrcpy --video-source=camera --camera-fps=60
```


## High speed capture

The Android camera API also supports a [high speed capture mode][high speed].

This mode is restricted to specific resolutions and frame rates, listed by
`--list-camera-sizes`.

```bash
scrcpy --video-source=camera --camera-size=1920x1080 --camera-high-speed --camera-fps=240
```

[high speed]: https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession


## Brace expansion tip

All camera options start with `--camera-`, so if your shell supports it, you can
benefit from [brace expansion] (for example, it is supported by _bash_ and
_zsh_):

```bash
scrcpy --video-source=camera --camera-{facing=back,ar=16:9,high-speed,fps=120}
```

This will be expanded as:

```bash
scrcpy --video-source=camera --camera-facing=back --camera-ar=16:9 --camera-high-speed --camera-fps=120
```

[brace expansion]: https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html


## Torch

The camera torch can be turned on at startup by `--camera-torch`:

```
scrcpy --video-source=camera --camera-torch
```

It can also be turned on and off dynamically with <kbd>MOD</kbd>+<kbd>t</kbd>
and <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>t</kbd>, respectively.


## Zoom

The camera zoom can be set with `--camera-zoom`:

```bash
scrcpy --video-source=camera --camera-zoom=1.5
```

It can also be adjusted dynamically using <kbd>MOD</kbd>+<kbd>↑</kbd> _(up)_ and
<kbd>MOD</kbd>+<kbd>↓</kbd> _(down)_.


## Webcam

Combined with the [V4L2](v4l2.md) feature on Linux, the Android device camera
may be used as a webcam on the computer.

---

## File: doc/connection.md

# Connection

## Selection

If exactly one device is connected (i.e. listed by `adb devices`), then it is
automatically selected.

However, if there are multiple devices connected, you must specify the one to
use in one of 4 ways:
 - by its serial:
   ```bash
   scrcpy --serial=0123456789abcdef
   scrcpy -s 0123456789abcdef   # short version

   # the serial is the ip:port if connected over TCP/IP (same behavior as adb)
   scrcpy --serial=192.168.1.1:5555
   ```
 - the one connected over USB (if there is exactly one):
   ```bash
   scrcpy --select-usb
   scrcpy -d   # short version
   ```
 - the one connected over TCP/IP (if there is exactly one):
   ```bash
   scrcpy --select-tcpip
   scrcpy -e   # short version
   ```
 - a device already listening on TCP/IP (see [below](#tcpip-wireless)):
   ```bash
   scrcpy --tcpip=192.168.1.1:5555
   scrcpy --tcpip=192.168.1.1        # default port is 5555
   ```

The serial may also be provided via the environment variable `ANDROID_SERIAL`
(also used by `adb`):

```bash
# in bash
export ANDROID_SERIAL=0123456789abcdef
scrcpy
```

```cmd
:: in cmd
set ANDROID_SERIAL=0123456789abcdef
scrcpy
```

```powershell
# in PowerShell
$env:ANDROID_SERIAL = '0123456789abcdef'
scrcpy
```


## TCP/IP (wireless)

_Scrcpy_ uses `adb` to communicate with the device, and `adb` can [connect] to a
device over TCP/IP. The device must be connected on the same network as the
computer.

[connect]: https://developer.android.com/studio/command-line/adb.html#wireless


### Automatic

An option `--tcpip` allows to configure the connection automatically. There are
two variants.

If _adb_ TCP/IP mode is disabled on the device (or if you don't know the IP
address), connect the device over USB, then run:

```bash
scrcpy --tcpip   # without arguments
```

It will automatically find the device IP address and adb port, enable TCP/IP
mode if necessary, then connect to the device before starting.

If the device (accessible at 192.168.1.1 in this example) already listens on a
port (typically 5555) for incoming _adb_ connections, then run:

```bash
scrcpy --tcpip=192.168.1.1       # default port is 5555
scrcpy --tcpip=192.168.1.1:5555
```

Prefix the address with a '+' to force a reconnection:

```bash
scrcpy --tcpip=+192.168.1.1
```


### Manual

Alternatively, it is possible to enable the TCP/IP connection manually using
`adb`:

1. Plug the device into a USB port on your computer.
2. Connect the device to the same Wi-Fi network as your computer.
3. Get your device IP address, in Settings → About phone → Status, or by
   executing this command:

    ```bash
    adb shell ip route | awk '{print $9}'
    ```

4. Enable `adb` over TCP/IP on your device: `adb tcpip 5555`.
5. Unplug your device.
6. Connect to your device: `adb connect DEVICE_IP:5555` _(replace `DEVICE_IP`
with the device IP address you found)_.
7. Run `scrcpy` as usual.
8. Run `adb disconnect` once you're done.

Since Android 11, a [wireless debugging option][adb-wireless] allows you to
bypass having to physically connect your device to your computer.

[adb-wireless]: https://developer.android.com/studio/command-line/adb#wireless-android11-command-line


## Autostart

A small tool (by the scrcpy author) allows you to run arbitrary commands
whenever a new Android device is connected: [AutoAdb]. It can be used to start
scrcpy:

```bash
autoadb scrcpy -s '{}'
```

[AutoAdb]: https://github.com/rom1v/autoadb

---

## File: doc/control.md

# Control

## Read-only

To disable controls (everything which can interact with the device: input keys,
mouse events, drag&drop files):

```bash
scrcpy --no-control
scrcpy -n   # short version
```

## Keyboard and mouse

Read [keyboard](keyboard.md) and [mouse](mouse.md).


## Control only

To control the device without mirroring:

```bash
scrcpy --no-video --no-audio
```

By default, the mouse is disabled when video playback is turned off.

To control the device using a relative mouse, enable UHID mouse mode:

```bash
scrcpy --no-video --no-audio --mouse=uhid
scrcpy --no-video --no-audio -M  # short version
```

To also use a UHID keyboard, set it explicitly:

```bash
scrcpy --no-video --no-audio --mouse=uhid --keyboard=uhid
scrcpy --no-video --no-audio -MK  # short version
```

To use AOA instead (over USB only):

```bash
scrcpy --no-video --no-audio --keyboard=aoa --mouse=aoa
```


## Copy-paste

Any time the Android clipboard changes, it is automatically synchronized to the
computer clipboard.

Any <kbd>Ctrl</kbd> shortcut is forwarded to the device. In particular:
 - <kbd>Ctrl</kbd>+<kbd>c</kbd> typically copies
 - <kbd>Ctrl</kbd>+<kbd>x</kbd> typically cuts
 - <kbd>Ctrl</kbd>+<kbd>v</kbd> typically pastes (after computer-to-device
   clipboard synchronization)

This typically works as you expect.

The actual behavior depends on the active application though. For example,
_Termux_ sends SIGINT on <kbd>Ctrl</kbd>+<kbd>c</kbd> instead, and _K-9 Mail_
composes a new message.

To copy, cut and paste in such cases (but only supported on Android >= 7):
 - <kbd>MOD</kbd>+<kbd>c</kbd> injects `COPY`
 - <kbd>MOD</kbd>+<kbd>x</kbd> injects `CUT`
 - <kbd>MOD</kbd>+<kbd>v</kbd> injects `PASTE` (after computer-to-device
   clipboard synchronization)

In addition, <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd> injects the computer
clipboard text as a sequence of key events. This is useful when the component
does not accept text pasting (for example in _Termux_), but it can break
non-ASCII content.

**WARNING:** Pasting the computer clipboard to the device (either via
<kbd>Ctrl</kbd>+<kbd>v</kbd> or <kbd>MOD</kbd>+<kbd>v</kbd>) copies the content
into the Android clipboard. As a consequence, any Android application could read
its content. You should avoid pasting sensitive content (like passwords) that
way.

Some Android devices do not behave as expected when setting the device clipboard
programmatically. An option `--legacy-paste` is provided to change the behavior
of <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>MOD</kbd>+<kbd>v</kbd> so that they
also inject the computer clipboard text as a sequence of key events (the same
way as <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).

To disable automatic clipboard synchronization, use
`--no-clipboard-autosync`.


## Pinch-to-zoom, rotate and tilt simulation

To simulate "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-and-move_.

More precisely, hold down <kbd>Ctrl</kbd> while pressing the left-click button.
Until the left-click button is released, all mouse movements scale and rotate
the content (if supported by the app) relative to the center of the screen.

https://github.com/Genymobile/scrcpy/assets/543275/26c4a920-9805-43f1-8d4c-608752d04767

To simulate a vertical tilt gesture: <kbd>Shift</kbd>+_click-and-move-up-or-down_.

https://github.com/Genymobile/scrcpy/assets/543275/1e252341-4a90-4b29-9d11-9153b324669f

Similarly, to simulate a horizontal tilt gesture:
<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+_click-and-move-left-or-right_.

Technically, _scrcpy_ generates additional touch events from a "virtual finger"
at a location inverted through the center of the screen. When pressing
<kbd>Ctrl</kbd> the _x_ and _y_ coordinates are inverted. Using <kbd>Shift</kbd>
only inverts _x_, whereas using <kbd>Ctrl</kbd>+<kbd>Shift</kbd> only inverts
_y_.

This only works for the default mouse mode (`--mouse=sdk`).


## File drop

### Install APK

To install an APK, drag & drop an APK file (ending with `.apk`) to the _scrcpy_
window.

There is no visual feedback, a log is printed to the console.


### Push file to device

To push a file to `/sdcard/Download/` on the device, drag & drop a (non-APK)
file to the _scrcpy_ window.

There is no visual feedback, a log is printed to the console.

The target directory can be changed on start:

```bash
scrcpy --push-target=/sdcard/Movies/
```

After each successful push, _scrcpy_ requests the media scanner to scan the
"push directory" so that the new files immediately appear in media apps.

Note that some gallery apps only show files from a fixed list of folders
(typically `DCIM/Camera`) in their main view; the file is then still reachable
through the system Photo Picker and the folder view, but may not appear on the
gallery home screen.

---

## File: doc/develop.md

# scrcpy for developers

## Overview

This application is composed of two parts:
 - the server (`scrcpy-server`), to be executed on the device,
 - the client (the `scrcpy` binary), executed on the host computer.

The client is responsible to push the server to the device and start its
execution.

The client and the server establish communication using separate sockets for
video, audio and controls. Any of them may be disabled (but not all), so
there are 1, 2 or 3 socket(s).

The server initially sends the device name on the first socket (it is used for
the scrcpy window title), then each socket is used for its own purpose. All
reads and writes are performed from a dedicated thread for each socket, both on
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 `--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
`--audio-source=mic` is specified), with some additional headers for each
packet. The client decodes the stream, attempts to keep a minimal latency by
maintaining an average buffering. The [blog post][scrcpy2] of the scrcpy 2.0
release gives more details about the audio feature.

If control is enabled, then the client captures relevant keyboard and mouse
events, that it transmits to the server, which injects them to the device. This
is the only socket which is used in both direction: input events are sent from
the client to the device, and when the device clipboard changes, the new content
is sent from the device to the client to support seamless copy-paste.

[scrcpy2]: https://blog.rom1v.com/2023/03/scrcpy-2-0-with-audio/

Note that the client-server roles are expressed at the application level:

 - the server _serves_ video and audio streams, and handle requests from the
   client,
 - the client _controls_ the device through the server.

However, by default (when `--force-adb-forward` is not set), the roles are
reversed at the network level:

 - the client opens a server socket and listen on a port before starting the
   server,
 - the server connects to the client.

This role inversion guarantees that the connection will not fail due to race
conditions without polling.


## Server


### Privileges

Capturing the screen requires some privileges, which are granted to `shell`.

The server is a Java application (with a [`public static void main(String...
args)`][main] method), compiled against the Android framework, and executed as
`shell` on the Android device.

[main]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/Server.java#L212

To run such a Java application, the classes must be [_dexed_][dex] (typically,
to `classes.dex`). If `my.package.MainClass` is the main class, compiled to
`classes.dex`, pushed to the device in `/data/local/tmp`, then it can be run
with:

    adb shell CLASSPATH=/data/local/tmp/classes.dex app_process / my.package.MainClass

_The path `/data/local/tmp` is a good candidate to push the server, since it's
readable and writable by `shell`, but not world-writable, so a malicious
application may not replace the server just before the client executes it._

Instead of a raw _dex_ file, `app_process` accepts a _jar_ containing
`classes.dex` (e.g. an [APK]). For simplicity, and to benefit from the gradle
build system, the server is built to an (unsigned) APK (renamed to
`scrcpy-server.jar`).

[dex]: https://en.wikipedia.org/wiki/Dalvik_(software)
[apk]: https://en.wikipedia.org/wiki/Android_application_package


### Hidden methods

Although compiled against the Android framework, [hidden] methods and classes are
not directly accessible (and they may differ from one Android version to
another).

They can be called using reflection though. The communication with hidden
components is provided by [_wrappers_ classes][wrappers] and [aidl].

[hidden]: https://stackoverflow.com/a/31908373/1987178
[wrappers]: https://github.com/Genymobile/scrcpy/tree/master/server/src/main/java/com/genymobile/scrcpy/wrappers
[aidl]: https://github.com/Genymobile/scrcpy/tree/master/server/src/main/aidl



### Execution

The server is started by the client basically by executing the following
commands:

```bash
adb push scrcpy-server /data/local/tmp/scrcpy-server.jar
adb forward tcp:27183 localabstract:scrcpy
adb shell CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 4.0
```

The first argument (`4.0` in the example) is the client scrcpy version. The
server fails if the client and the server do not have the exact same version.
The protocol between the client and the server may change from version to
version (see [protocol](#protocol) below), and there is no backward or forward
compatibility (there is no point to use different client and server versions).
This check allows to detect misconfiguration (running an older or newer server
by mistake).

It is followed by any number of arguments, in the form of `key=value` pairs.
Their order is irrelevant. The possible keys and associated value types can be
found in the [server][server-options] and [client][client-options] code.

[server-options]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/Options.java#L339
[client-options]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/app/src/server.c#L265

For example, if we execute `scrcpy -m1920 --no-audio`, then the server
execution will look like this:

```bash
# scid is a random number to identify different clients running on the same device
adb shell CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 4.0 scid=12345678 log_level=info audio=false max_size=1920
```

### Components

When executed, its [`main()`][main] method is executed (on the "main" thread).
It parses the arguments, establishes the connection with the client and starts
the other "components":
 - the **video** streamer: it captures the video screen and send encoded video
   packets on the _video_ socket (from the _video_ thread).
 - the **audio** streamer: it uses several threads to capture raw packets,
   submits them to encoding and retrieve encoded packets, which it sends on the
   _audio_ socket.
 - the **controller**: it receives _control messages_ (typically input events)
   on the _control_ socket from one thread, and sends _device messages_ (e.g. to
   transmit the device clipboard content to the client) on the same _control
   socket_ from another thread. Thus, the _control_ socket is used in both
   directions (contrary to the _video_ and _audio_ sockets).


### Screen video encoding

The screen capture is managed by [`ScreenCapture`] and the encoding is performed
by [`SurfaceEncoder`].

The video is encoded using the [`MediaCodec`] API. The codec encodes the content
of a `Surface` associated to the display, and writes the encoding packets to the
client (on the _video_ socket).

[`ScreenCapture`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/video/ScreenCapture.java
[`SurfaceEncoder`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java
[`MediaCodec`]: https://developer.android.com/reference/android/media/MediaCodec.html

On device rotation (or folding), the encoding session is reset and restarted.

New frames are produced only when changes occur on the surface. This avoids to
send unnecessary frames, but by default there might be drawbacks:

 - it does not send any frame on start if the device screen does not change,
 - after fast motion changes, the last frame may have poor quality.

Both problems are [solved][repeat] by the flag
[`KEY_REPEAT_PREVIOUS_FRAME_AFTER`][repeat-flag].

[repeat]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/video/SurfaceEncoder.java#L313-L314
[repeat-flag]: https://developer.android.com/reference/android/media/MediaFormat.html#KEY_REPEAT_PREVIOUS_FRAME_AFTER


### Audio encoding

Similarly, the audio is [captured] using an [`AudioRecord`], and [encoded] using
the [`MediaCodec`] asynchronous API.

More details are available on the [blog post][scrcpy2] introducing the audio feature.

[captured]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/audio/AudioDirectCapture.java
[encoded]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java
[`AudioRecord`]: https://developer.android.com/reference/android/media/AudioRecord


### Input events injection

_Control messages_ are received from the client by the [`Controller`] (run in a
separate thread). There are several types of input events:
 - keycode (cf [`KeyEvent`]),
 - text (special characters may not be handled by keycodes directly),
 - mouse motion/click,
 - mouse scroll,
 - other commands (e.g. to switch the screen on or to copy the clipboard).

Some of them need to inject input events to the system. To do so, they use the
_hidden_ method [`InputManager.injectInputEvent()`].

[`Controller`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/control/Controller.java
[`KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent.html
[`MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent.html
[`InputManager.injectInputEvent()`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java#L48



## Client

The client relies on [SDL], which provides cross-platform API for UI, input
events, threading, etc.

The video and audio streams are decoded by [FFmpeg].

[SDL]: https://www.libsdl.org
[ffmpeg]: https://ffmpeg.org/


### Initialization

The client parses the command line arguments, then [runs one of two code
paths][run]:
 - scrcpy in "normal" mode ([`scrcpy.c`])
 - scrcpy in [OTG mode](otg.md) ([`scrcpy_otg.c`])

[run]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/app/src/main.c#L93
[`scrcpy.c`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/app/src/scrcpy.c#L305-L306
[`scrcpy_otg.c`]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/app/src/usb/scrcpy_otg.c#L61-L62

In the remaining of this document, we assume that the "normal" mode is used
(read the code for the OTG mode).

On startup, the client:
 - opens the _video_, _audio_ and _control_ sockets;
 - pushes and starts the server on the device;
 - initializes its components (demuxers, decoders, recorder…).


### Video and audio streams

Depending on the arguments passed to `scrcpy`, several components may be used.
Here is an overview of the video and audio components:

```
                                                 V4L2 sink
                                               /
                                       decoder
                                     /         \
        VIDEO -------------> demuxer             display
                                     \
                                       recorder
                                     /
        AUDIO -------------> demuxer
                                     \
                                       decoder --- audio player
```

The _demuxer_ is responsible to extract video and audio packets (read some
header, split the video stream into packets at correct boundaries, etc.).

The demuxed packets may be sent to a _decoder_ (one per stream, to produce
frames) and to a recorder (receiving both video and audio stream to record a
single file). The packets are encoded on the device (by `MediaCodec`), but when
recording, they are _muxed_ (asynchronously) into a container (MKV or MP4) on
the client side.

Video frames are sent to the screen/display to be rendered in the scrcpy window.
They may also be sent to a [V4L2 sink](v4l2.md).

Audio "frames" (an array of decoded samples) are sent to the audio player.


### Controller

The _controller_ is responsible to send _control messages_ to the device. It
runs in a separate thread, to avoid I/O on the main thread.

On SDL event, received on the main thread, the _input manager_ creates
appropriate _control messages_. It is responsible to convert SDL events to
Android events. It then pushes the _control messages_ to a queue hold by the
controller. On its own thread, the controller takes messages from the queue,
that it serializes and sends to the client.


## Protocol

The protocol between the client and the server must be considered _internal_: it
may (and will) change at any time for any reason. Everything may change (the
number of sockets, the order in which the sockets must be opened, the data
format on the wire…) from version to version. A client must always be run with a
matching server version.

This section documents the current protocol in scrcpy 4.0.

### Connection

Firstly, the client sets up an adb tunnel:

```bash
# By default, a reverse redirection: the computer listens, the device connects
adb reverse localabstract:scrcpy_<SCID> tcp:27183

# As a fallback (or if --force-adb forward is set), a forward redirection:
# the device listens, the computer connects
adb forward tcp:27183 localabstract:scrcpy_<SCID>
```

(`<SCID>` is a 31-bit random number, so that it does not fail when several
scrcpy instances start "at the same time" for the same device.)

Then, up to 3 sockets are opened, in that order:
 - a _video_ socket
 - an _audio_ socket
 - a _control_ socket

Each one may be disabled (respectively by `--no-video`, `--no-audio` and
`--no-control`, directly or indirectly). For example, if `--no-audio` is set,
then the _video_ socket is opened first, then the _control_ socket.

On the _first_ socket opened (whichever it is), if the tunnel is _forward_, then
a [dummy byte] is sent from the device to the client. This allows to detect a
connection error (the client connection does not fail as long as there is an adb
forward redirection, even if nothing is listening on the device side).

Still on this _first_ socket, the device sends some [metadata][device meta] to
the client (currently only the device name, used as the window title, but there
might be other fields in the future).

[dummy byte]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L70
[device meta]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L155

You can read the [client][client-connection] and [server][server-connection]
code for more details.

[client-connection]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/app/src/server.c#L604-L605
[server-connection]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java#L56

Then each socket is used for its intended purpose.

### Video and audio

On the _video_ and _audio_ sockets, the device first sends the codec id (`u32`).

Valid codec ids for _video_ streams are:
 - `"h264"` (`0x68323634`)
 - `"h265"` (`0x68323635`)
 - `"av1"` (`0x00617631`)
 - `"vp8"` (`0x00767038`)
 - `"vp9"` (`0x00767039`)

Valid codec ids for _audio_ streams are:
 - `"opus"` (`0x6F707573`)
 - `"aac"` (`0x00616163`)
 - `"flac"` (`0x666C6163`)
 - `"raw"` (`0x00726177`)

For the _video_ stream, a _session packet_ (12 bytes) is sent for each capture
session (a session changes when the device rotates):

```
     byte 0   byte 1   byte 2   byte 3
    10000000 00000000 00000000 0000000R
    ^<------------------------------->^
    |               padding           |
     `- session packet flag            `- client resized flag

     byte 4   byte 5   byte 6   byte 7   byte 8   byte 9   byte 10  byte 11
    ........ ........ ........ ........ ........ ........ ........ ........
    <---------------------------------> <--------------------------------->
                video width                         video height
```

The "client resized" flag is used for _flex displays_ to indicate that the frame
size changed due to a client resize request (see [#6772]).

[#6772]: https://github.com/Genymobile/scrcpy/pull/6772

For the _audio_ stream, there are no _session packets_.

Then _media packets_ are sent, each containing the payload produced by
`MediaCodec`, prefixed by a 12-byte [frame header]:
 - media packet flag (`u1`)
 - config packet flag (`u1`)
 - key frame flag (`u1`)
 - PTS (`u61`)
 - packet size (`u32`)

Here is a schema describing the frame header:

```
    [. . . . . . . .|. . . .]. . . . . . . . . . . . . . . ...
     <-------------> <-----> <-----------------------------...
           PTS        packet        raw packet
                       size
     <--------------------->
           frame header

The most significant bits of the PTS are used for packet flags:

     byte 0   byte 1   byte 2   byte 3   byte 4   byte 5   byte 6   byte 7
    0CK..... ........ ........ ........ ........ ........ ........ ........
    ^^^<------------------------------------------------------------------>
    |||                                PTS
    || `- key frame
    | `-- config packet
     `--- media packet flag

     byte 8   byte 9   byte 10  byte 11
    ........ ........ ........ ........ ........ ........ . . .
    <---------------------------------> <---------------- . . .
               packet size                       raw packet

```

_Session packets_ and _media packets_ are distinguished by their first bit (the
MSB).

[frame header]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/device/Streamer.java#L107


### Controls

Controls messages are sent via a custom binary protocol.

The only documentation for this protocol is the set of unit tests on both sides:
 - `ControlMessage` (from client to device): [serialization](https://github.com/Genymobile/scrcpy/blob/master/app/tests/test_control_msg_serialize.c)
   | [deserialization](https://github.com/Genymobile/scrcpy/blob/master/server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java)
 - `DeviceMessage` (from device to client) [serialization](https://github.com/Genymobile/scrcpy/blob/master/server/src/test/java/com/genymobile/scrcpy/control/DeviceMessageWriterTest.java)
   | [deserialization](https://github.com/Genymobile/scrcpy/blob/master/app/tests/test_device_msg_deserialize.c)


## Standalone server

Although the server is designed to work for the scrcpy client, it can be used
with any client which uses the same protocol.

For simplicity, some [server-specific options] have been added to produce raw
streams easily:
 - `send_device_meta=false`: disable device metadata (in practice, the device
   name) sent on the _first_ socket
 - `send_frame_meta=false`: disable the 12-byte header for each packet
 - `send_dummy_byte`: disable the dummy byte sent on forward connections
 - `send_stream_meta`: disable codec and video size metadata
 - `raw_stream`: disable all the above

[server-specific options]: https://github.com/Genymobile/scrcpy/blob/19057b48afb9d5388bd143c6f885008f48055552/server/src/main/java/com/genymobile/scrcpy/Options.java#L542-L562

Concretely, here is how to expose a raw H.264 stream on a TCP socket:

```bash
adb push scrcpy-server-v4.0 /data/local/tmp/scrcpy-server-manual.jar
adb forward tcp:1234 localabstract:scrcpy
adb shell CLASSPATH=/data/local/tmp/scrcpy-server-manual.jar \
    app_process / com.genymobile.scrcpy.Server 4.0 \
    tunnel_forward=true audio=false control=false cleanup=false \
    raw_stream=true max_size=1920
```

As soon as a client connects over TCP on port 1234, the device will start
streaming the video. For example, VLC can play the video (although you will
experience a very high latency, more details [here][vlc-0latency]):

```bash
vlc -Idummy --demux=h264 --network-caching=0 tcp://localhost:1234
```

[vlc-0latency]: https://code.videolan.org/rom1v/vlc/-/merge_requests/20


## Hack

For more details, go read the code!

If you find a bug, or have an awesome idea to implement, please discuss and
contribute ;-)


### Debug the server

The server is pushed to the device by the client on startup.

To debug it, enable the server debugger during configuration:

```bash
meson setup x -Dserver_debugger=true
# or, if x is already configured
meson configure x -Dserver_debugger=true
```

Then recompile, and run scrcpy.

For Android < 11, it will start a debugger on port 5005 on the device and wait:
Redirect that port to the computer:

```bash
adb forward tcp:5005 tcp:5005
```

For Android >= 11, first find the listening port:

```bash
adb jdwp
# press Ctrl+C to interrupt
```

Then redirect the resulting PID:

```bash
adb forward tcp:5005 jdwp:XXXX  # replace XXXX
```

In Android Studio, _Run_ > _Debug_ > _Edit configurations..._ On the left, click
on `+`, _Remote_, and fill the form:

 - Host: `localhost`
 - Port: `5005`

Then click on _Debug_.

---

## File: doc/device.md

# Device

Some command line arguments perform actions on the device itself while scrcpy is
running.


## Keep active

To prevent the device from turning off due to inactivity, `--keep-active`
periodically signals user activity to the system:

```bash
scrcpy --keep-active
```


## Stay awake

To prevent the device from sleeping after a delay **when the device is plugged
in**:

```bash
scrcpy --stay-awake
scrcpy -w
```

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 stay_on_while_plugged_in 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
```


## Screen off timeout

The Android screen automatically turns off after some delay.

To change this delay while scrcpy is running:

```bash
scrcpy --screen-off-timeout=300  # 300 seconds (5 minutes)
```

The initial value is restored on exit.

It is possible to change this setting manually:

```bash
# get the current screen_off_timeout value
adb shell settings get system screen_off_timeout
# set a new value (in milliseconds)
adb shell settings put system screen_off_timeout 30000
```

Note that the Android value is in milliseconds, but the scrcpy command line
argument is in seconds.


## Turn screen off

It is possible to turn the device screen off while mirroring on start with a
command-line option:

```bash
scrcpy --turn-screen-off
scrcpy -S   # short version
```

Or by pressing <kbd>MOD</kbd>+<kbd>o</kbd> at any time (see
[shortcuts](shortcuts.md)).

To turn it back on, press <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>o</kbd>.

On Android, the `POWER` button always turns the screen on. For convenience, if
`POWER` is sent via _scrcpy_ (via right-click or <kbd>MOD</kbd>+<kbd>p</kbd>),
it will force to turn the screen off after a small delay (on a best effort
basis). The physical `POWER` button will still cause the screen to be turned on.

It can also be useful to prevent the device from sleeping:

```bash
scrcpy --turn-screen-off --stay-awake
scrcpy -Sw   # short version
```

Since Android 15, it is possible to change this setting manually:

```bash
# 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

For presentations, it may be useful to show physical touches (on the physical
device). Android exposes this feature in _Developers options_.

_Scrcpy_ provides an option to enable this feature on start and restore the
initial value on exit:

```bash
scrcpy --show-touches
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

To turn the device screen off when closing _scrcpy_:

```bash
scrcpy --power-off-on-close
```

## Power on on start

By default, on start, the device is powered on. To prevent this behavior:

```bash
scrcpy --no-power-on
```


## Start Android app

To list the Android apps installed on the device:

```bash
scrcpy --list-apps
```

An app, selected by its package name, can be launched on start:

```bash
scrcpy --start-app=org.mozilla.firefox
```

This feature can be used to run an app in a [virtual
display](virtual-display.md):

```bash
scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
```

The app can be optionally forced-stop before being started, by adding a `+`
prefix:

```bash
scrcpy --start-app=+org.mozilla.firefox
```

For convenience, it is also possible to select an app by its name, by adding a
`?` prefix:

```bash
scrcpy --start-app=?firefox
```

But retrieving app names may take some time (sometimes several seconds), so
passing the package name is recommended.

The `+` and `?` prefixes can be combined (in that order):

```bash
scrcpy --start-app=+?firefox
```

---

## File: doc/gamepad.md

# Gamepad

Several gamepad input modes are available:

 - `--gamepad=disabled` (default)
 - `--gamepad=uhid` (or `-G`): simulates physical HID gamepads using the UHID
   kernel module on the device
 - `--gamepad=aoa`: simulates physical HID gamepads using the AOAv2 protocol


## Physical gamepad simulation

Two modes allow to simulate physical HID gamepads on the device, one for each
physical gamepad plugged into the computer.


### UHID

This mode simulates physical HID gamepads using the [UHID] kernel module on the
device.

[UHID]: https://kernel.org/doc/Documentation/hid/uhid.txt

To enable UHID gamepads, use:

```bash
scrcpy --gamepad=uhid
scrcpy -G  # short version
```

Note: UHID may not work on old Android versions due to permission errors.


### AOA

This mode simulates physical HID gamepads using the [AOAv2] protocol.

[AOAv2]: https://source.android.com/devices/accessories/aoa2#hid-support

To enable AOA gamepads, use:

```bash
scrcpy --gamepad=aoa
```

Contrary to the other mode, it works at the USB level directly (so it only works
over USB).

It does not use the scrcpy server, and does not require `adb` (USB debugging).
Therefore, it is possible to control the device (but not mirror) even with USB
debugging disabled (see [OTG](otg.md)).

Note: For some reason, in this mode, Android detects multiple physical gamepads
as a single misbehaving one. Use UHID if you need multiple gamepads.

Note: On Windows, it may only work in [OTG mode](otg.md), not while mirroring
(it is not possible to open a USB device if it is already open by another
process like the _adb daemon_).

---

## File: doc/keyboard.md

# Keyboard

Several keyboard input modes are available:

 - `--keyboard=sdk` (default)
 - `--keyboard=uhid` (or `-K`): simulates a physical HID keyboard using the UHID
   kernel module on the device
 - `--keyboard=aoa`: simulates a physical HID keyboard using the AOAv2 protocol
 - `--keyboard=disabled`

By default, `sdk` is used, but if you use scrcpy regularly, it is recommended to
use [`uhid`](#uhid) and configure the keyboard layout once and for all.


## SDK keyboard

In this mode (`--keyboard=sdk`, or if the parameter is omitted), keyboard input
events are injected at the Android API level. It works everywhere, but it is
limited to ASCII and some other characters.

Note that on some devices, an additional option must be enabled in developer
options for this keyboard mode to work. See
[prerequisites](/README.md#prerequisites).

Additional parameters (specific to `--keyboard=sdk`) described below allow to
customize the behavior.


### Text injection preference

Two kinds of [events][textevents] are generated when typing text:
 - _key events_, signaling that a key is pressed or released;
 - _text events_, signaling that a text has been entered.

By default, numbers and "special characters" are inserted using text events, but
letters are injected using key events, so that the keyboard behaves as expected
in games (typically for WASD keys).

But this may [cause issues][prefertext]. If you encounter such a problem, you
can inject letters as text (or just switch to [UHID](#uhid)):

```bash
scrcpy --prefer-text
```

(but this will break keyboard behavior in games)

On the contrary, you could force to always inject raw key events:

```bash
scrcpy --raw-key-events
```

[textevents]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-text-input
[prefertext]: https://github.com/Genymobile/scrcpy/issues/650#issuecomment-512945343


### Key repeat

By default, holding a key down generates repeated key events. Ths can cause
performance problems in some games, where these events are useless anyway.

To avoid forwarding repeated key events:

```bash
scrcpy --no-key-repeat
```


## Physical keyboard simulation

Two modes allow to simulate a physical HID keyboard on the device.

To work properly, it is necessary to configure (once and for all) the keyboard
layout on the device to match that of the computer.

The configuration page can be opened in one of the following ways:
 - from the scrcpy window (when `uhid` or `aoa` is used), by pressing
   <kbd>MOD</kbd>+<kbd>k</kbd> (see [shortcuts](shortcuts.md))
 - from the device, in Settings → System → Languages and input → Physical
   devices
 - from a terminal on the computer, by executing `adb shell am start -a
   android.settings.HARD_KEYBOARD_SETTINGS`

From this configuration page, it is also possible to enable or disable on-screen
keyboard.


### UHID

This mode simulates a physical HID keyboard using the [UHID] kernel module on the
device.

[UHID]: https://kernel.org/doc/Documentation/hid/uhid.txt

To enable UHID keyboard, use:

```bash
scrcpy --keyboard=uhid
scrcpy -K  # short version
```

Once the keyboard layout is configured (see above), it is the best mode for
using the keyboard while mirroring:

 - it works for all characters and IME (contrary to `--keyboard=sdk`)
 - the on-screen keyboard can be disabled (contrary to `--keyboard=sdk`)
 - it works over TCP/IP (wirelessly) (contrary to `--keyboard=aoa`)
 - there are no issues on Windows (contrary to `--keyboard=aoa`)

One drawback is that it may not work on old Android versions due to permission
errors.


### AOA

This mode simulates a physical HID keyboard using the [AOAv2] protocol.

[AOAv2]: https://source.android.com/devices/accessories/aoa2#hid-support

To enable AOA keyboard, use:

```bash
scrcpy --keyboard=aoa
```

Contrary to the other modes, it works at the USB level directly (so it only
works over USB).

It does not use the scrcpy server, and does not require `adb` (USB debugging).
Therefore, it is possible to control the device (but not mirror) even with USB
debugging disabled (see [OTG](otg.md)).

Note: On Windows, it may only work in [OTG mode](otg.md), not while mirroring
(it is not possible to open a USB device if it is already open by another
process like the _adb daemon_).