# ws scrcpy
Web client for [Genymobile/scrcpy][scrcpy] and more.
## Requirements
Browser must support the following technologies:
* WebSockets
* Media Source Extensions and h264 decoding;
* WebWorkers
* WebAssembly
Server:
* Node.js v10+
* node-gyp ([installation](https://github.com/nodejs/node-gyp#installation))
* `adb` executable must be available in the PATH environment variable
Device:
* Android 5.0+ (API 21+)
* Enabled [adb debugging](https://developer.android.com/studio/command-line/adb.html#Enabling)
* On some devices, you also need to enable
[an additional option](https://github.com/Genymobile/scrcpy/issues/70#issuecomment-373286323)
to control it using keyboard and mouse.
## Build and Start
Make sure you have installed [node.js](https://nodejs.org/en/download/),
[node-gyp](https://github.com/nodejs/node-gyp) and
[build tools](https://github.com/nodejs/node-gyp#installation)
```shell
git clone https://github.com/NetrisTV/ws-scrcpy.git
cd ws-scrcpy
## For stable version find latest tag and switch to it:
# git tag -l
# git checkout vX.Y.Z
npm install
npm start
```
## Supported features
### Android
#### Screen casting
The modified [version][fork] of [Genymobile/scrcpy][scrcpy] used to stream
H264-video, which then decoded by one of included decoders:
##### Mse Player
Based on [xevokk/h264-converter][xevokk/h264-converter].
HTML5 Video.
Requires [Media Source API][MSE] and `video/mp4; codecs="avc1.42E01E"`
[support][isTypeSupported]. Creates mp4 containers from NALU, received from a
device, then feeds them to [MediaSource][MediaSource]. In theory, it can use
hardware acceleration.
##### Broadway Player
Based on [mbebenita/Broadway][broadway] and
[131/h264-live-player][h264-live-player].
Software video-decoder compiled into wasm-module.
Requires [WebAssembly][wasm] and preferably [WebGL][webgl] support.
##### TinyH264 Player
Based on [udevbe/tinyh264][tinyh264].
Software video-decoder compiled into wasm-module. A slightly updated version of
[mbebenita/Broadway][broadway].
Requires [WebAssembly][wasm], [WebWorkers][workers], [WebGL][webgl] support.
##### WebCodecs Player
Decoding is done by browser built-in (software/hardware) media decoder.
Requires [WebCodecs][webcodecs] support. At the moment, available only in
[Chromium](https://www.chromestatus.com/feature/5669293909868544) and derivatives.
#### Remote control
* Touch events (including multi-touch)
* Multi-touch emulation: CTRL to start with center at the center of
the screen, SHIFT + CTRL to start with center at the
current point
* Mouse wheel and touchpad vertical/horizontal scrolling
* Capturing keyboard events
* Injecting text (ASCII only)
* Copy to/from device clipboard
* Device "rotation"
#### File push
Drag & drop an APK file to push it to the `/data/local/tmp` directory. You can
install it manually from the included [xtermjs/xterm.js][xterm.js] terminal
emulator (see below).
#### Remote shell
Control your device from `adb shell` in your browser.
#### Debug WebPages/WebView
[/docs/Devtools.md](/docs/Devtools.md)
#### File listing
* List files
* Upload files by drag & drop
* Download files
### iOS
***Experimental Feature***: *is not built by default*
(see [custom build](#custom-build))
#### Screen Casting
Requires [ws-qvh][ws-qvh] available in `PATH`.
Tips for a stable QuickTime-over-USB stream: set the device's **Auto-Lock to
Never** (a locked screen stops the stream), connect the iPhone **directly**
(no USB hub), and do not run a standalone `ws-qvh`/`qvh` capture against the
same device while ws-scrcpy is streaming — only one process may hold a device.
#### MJPEG Server
> ⚠️ **Temporarily suspended.** After the migration to a standalone Appium
> (see [Remote control](#remote-control)) the WDA-MJPEG video path is not wired
> up and is planned to be restored in a follow-up. iOS screen casting currently
> runs via `ws-qvh` (see above).
Enable `USE_WDA_MJPEG_SERVER` in the build configuration file
(see [custom build](#custom-build)).
Alternative way to stream screen content. It does not
require additional software as `ws-qvh`, but may require more resources as each
frame encoded as jpeg image.
#### Remote control
Device control is provided by [appium/WebDriverAgent][WebDriverAgent], driven
through a modern [Appium][appium] server over the W3C WebDriver protocol.
ws-scrcpy bundles Appium (it is a dependency, and a `postinstall` step pins the
XCUITest driver into a project-local `.appium-home`), spawns it as a child
process on startup, and forwards control commands to it over HTTP — no global
Appium installation is required.
Supported actions:
* Simple touch
* Scroll / swipe
* Home button click
##### One-time device setup (real iOS device)
WebDriverAgent has to be built, signed and trusted on the device once:
1. Open the WDA project in Xcode — `WebDriverAgent.xcodeproj` under
`.appium-home/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent/`
(or under `$APPIUM_HOME/…` if you point Appium elsewhere). Select the
`WebDriverAgentRunner` scheme, set your **Team** and a unique **Bundle
Identifier**, and run it on the device once (`⌘U`).
2. On the device: **trust** the developer certificate
(`Settings → General → VPN & Device Management`) and enable **Developer
Mode** (`Settings → Privacy & Security → Developer Mode`, iOS 16+).
3. (Optional) enable `AssistiveTouch`: `Settings → General → Accessibility`.
See Appium's [real-device configuration guide][wda-real-device] for the full
WebDriverAgent setup. After this one-time step ws-scrcpy builds and launches WDA
on its own.
> **Be patient on the first control action.** Appium builds and launches
> WebDriverAgent on demand, which can take a couple of minutes the first time —
> the screen may look unresponsive until WDA is up. A free Apple developer
> account's provisioning expires every 7 days (re-sign weekly); a paid account
> avoids this.
##### iOS control configuration (environment variables)
| Variable | Purpose |
| --- | --- |
| `WDA_TEAM_ID` | Apple Team ID used to sign WebDriverAgent (the certificate's `OU`) |
| `WDA_SIGNING_ID` | Signing identity (default `Apple Development`) |
| `WDA_BUNDLE_ID` | Unique WDA bundle id, e.g. `com..WebDriverAgentRunner` |
| `WDA_PLATFORM_VERSION` | iOS version of the device (silences a driver warning) |
| `WDA_USE_PREBUILT` | `true` to reuse an already built/installed WDA (skip the rebuild) |
| `WS_SCRCPY_DEBUG` | Verbose logs — surfaces the Appium (incl. xcodebuild) and `ws-qvh` output in the server console |
| `APPIUM_BIN` / `APPIUM_HOME` / `APPIUM_PORT` / `APPIUM_LOG_LEVEL` | Override the bundled Appium binary, driver home, port or log level |
> **`xcodebuild failed with code 65`** almost always means WebDriverAgent could
> not be **signed or launched** on the device (untrusted certificate, Developer
> Mode off, wrong Team ID, or expired provisioning) — it is not a build error in
> ws-scrcpy. Run with `WS_SCRCPY_DEBUG=1` to surface the underlying xcodebuild
> error and follow the [real-device configuration guide][wda-real-device].
## Custom Build
You can customize project before build by overriding the
[default configuration](/webpack/default.build.config.json) in
[build.config.override.json](/build.config.override.json):
* `INCLUDE_APPL` - include code for iOS device tracking and control
* `INCLUDE_GOOG` - include code for Android device tracking and control
* `INCLUDE_ADB_SHELL` - [remote shell](#remote-shell) for android devices
([xtermjs/xterm.js][xterm.js], [Tyriar/node-pty][node-pty])
* `INCLUDE_DEV_TOOLS` - [dev tools](#debug-webpageswebview) for web pages and
web views on android devices
* `INCLUDE_FILE_LISTING` - minimalistic [file management](#file-listing)
* `USE_BROADWAY` - include [Broadway Player](#broadway-player)
* `USE_H264_CONVERTER` - include [Mse Player](#mse-player)
* `USE_TINY_H264` - include [TinyH264 Player](#tinyh264-player)
* `USE_WEBCODECS` - include [WebCodecs Player](#webcodecs-player)
* `USE_WDA_MJPEG_SERVER` - configure WebDriverAgent to start MJPEG server
_(temporarily suspended, see [MJPEG Server](#mjpeg-server))_
* `USE_QVH_SERVER` - include support for [ws-qvh][ws-qvh]
* `SCRCPY_LISTENS_ON_ALL_INTERFACES` - WebSocket server in `scrcpy-server.jar`
will listen for connections on all available interfaces. When `true`, it allows
connecting to device directly from a browser. Otherwise, the connection must be
established over adb.
## Run configuration
You can specify a path to a configuration file in `WS_SCRCPY_CONFIG`
environment variable.
If you want to have another pathname than "/" you can specify it in the
`WS_SCRCPY_PATHNAME` environment variable.
Configuration file format: [Configuration.d.ts](/src/types/Configuration.d.ts).
Configuration file example: [config.example.yaml](/config.example.yaml).
## Known issues
* The server on the Android Emulator listens on the internal interface and not
available from the outside. Select `proxy over adb` from the interfaces list.
* TinyH264Player may fail to start, try to reload the page.
* MsePlayer reports too many dropped frames in quality statistics: needs
further investigation.
* On Safari file upload does not show progress (it works in one piece).
* iOS screen casting can be slow to start — if the picture does not appear,
reload the tab a few times (or replug the device) until the QuickTime stream
catches; once it does, it stays stable. An empty player does not necessarily
mean it is broken.
* iOS control: `xcodebuild failed with code 65` is a WebDriverAgent signing /
launch issue, not a build error — see [Remote control](#remote-control).
## Security warning
Be advised and keep in mind:
* There is no encryption between browser and node.js server (you can [configure](#run-configuration) HTTPS).
* There is no encryption between browser and WebSocket server on android device.
* There is no authorization on any level.
* The modified version of scrcpy with integrated WebSocket server is listening
for connections on all network interfaces (see [custom build](#custom-build)).
* The modified version of scrcpy will keep running after the last client
disconnected.
## Related projects
* [Genymobile/scrcpy][scrcpy]
* [xevokk/h264-converter][xevokk/h264-converter]
* [131/h264-live-player][h264-live-player]
* [mbebenita/Broadway][broadway]
* [DeviceFarmer/adbkit][adbkit]
* [xtermjs/xterm.js][xterm.js]
* [udevbe/tinyh264][tinyh264]
* [danielpaulus/quicktime_video_hack][qvh]
## scrcpy websocket fork
Currently, support of WebSocket protocol added to v1.19 of scrcpy
* [Prebuilt package](/vendor/Genymobile/scrcpy/scrcpy-server.jar)
* [Source code][fork]
[fork]: https://github.com/NetrisTV/scrcpy/tree/feature/websocket-v1.19.x
[scrcpy]: https://github.com/Genymobile/scrcpy
[xevokk/h264-converter]: https://github.com/xevokk/h264-converter
[h264-live-player]: https://github.com/131/h264-live-player
[broadway]: https://github.com/mbebenita/Broadway
[adbkit]: https://github.com/DeviceFarmer/adbkit
[xterm.js]: https://github.com/xtermjs/xterm.js
[tinyh264]: https://github.com/udevbe/tinyh264
[node-pty]: https://github.com/Tyriar/node-pty
[WebDriverAgent]: https://github.com/appium/WebDriverAgent
[appium]: https://appium.io
[wda-real-device]: https://appium.github.io/appium-xcuitest-driver/latest/preparation/real-device-config/
[qvh]: https://github.com/danielpaulus/quicktime_video_hack
[ws-qvh]: https://github.com/NetrisTV/ws-qvh
[MSE]: https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API
[isTypeSupported]: https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/isTypeSupported
[MediaSource]: https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
[wasm]: https://developer.mozilla.org/en-US/docs/WebAssembly
[webgl]: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
[workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
[webcodecs]: https://w3c.github.io/webcodecs/