Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Vimont
0200760f87 Determine debugger command at runtime
When server_debugger is enabled, retrieve the device SDK version to
execute the correct command.

PR #5466 <https://github.com/Genymobile/scrcpy/pull/5466>
2024-11-17 15:01:05 +01:00
225 changed files with 2132 additions and 5224 deletions

View File

@@ -6,15 +6,11 @@ on:
name:
description: 'Version name (default is ref name)'
env:
# $VERSION is used by release scripts
VERSION: ${{ github.event.inputs.name || github.ref_name }}
jobs:
test-scrcpy-server:
build-scrcpy-server:
runs-on: ubuntu-latest
env:
GRADLE: gradle # use native gradle instead of ./gradlew in scripts
GRADLE: gradle # use native gradle instead of ./gradlew in release.mk
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -26,45 +22,16 @@ jobs:
java-version: '17'
- name: Test scrcpy-server
run: release/test_server.sh
run: make -f release.mk test-server
build-scrcpy-server:
runs-on: ubuntu-latest
env:
GRADLE: gradle # use native gradle instead of ./gradlew in scripts
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build scrcpy-server
run: make -f release.mk build-server
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'
- name: Build
run: release/build_server.sh
- name: Upload artifact
- name: Upload scrcpy-server artifact
uses: actions/upload-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/scrcpy-server
test-build-scrcpy-server-without-gradle:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '17'
- name: Build without gradle
run: server/build_without_gradle.sh
path: build-server/server/scrcpy-server
test-client:
runs-on: ubuntu-latest
@@ -77,51 +44,15 @@ jobs:
sudo apt update
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
libv4l-dev
- name: Test
run: release/test_client.sh
build-linux-x86_64:
runs-on: ubuntu-22.04
steps:
- name: Check architecture
run: |
arch=$(uname -m)
if [[ "$arch" != x86_64 ]]
then
echo "Unexpected architecture: $arch" >&2
exit 1
fi
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
libv4l-dev
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev
- name: Build
run: release/build_linux.sh x86_64
# upload-artifact does not preserve permissions
- name: Tar
run: |
cd release/work/build-linux-x86_64
mkdir dist-tar
cd dist-tar
tar -C .. -cvf dist.tar.gz dist/
meson setup d -Db_sanitize=address,undefined
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-linux-x86_64-intermediate
path: release/work/build-linux-x86_64/dist-tar/
- name: Test
run: |
meson test -Cd
build-win32:
runs-on: ubuntu-latest
@@ -137,22 +68,17 @@ jobs:
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
mingw-w64 mingw-w64-tools libz-mingw-w64-dev
- name: Build
run: release/build_windows.sh 32
- name: Workaround for old meson version run by Github Actions
run: sed -i 's/^pkg-config/pkgconfig/' cross_win32.txt
# upload-artifact does not preserve permissions
- name: Tar
run: |
cd release/work/build-win32
mkdir dist-tar
cd dist-tar
tar -C .. -cvf dist.tar.gz dist/
- name: Build scrcpy win32
run: make -f release.mk build-win32
- name: Upload artifact
- name: Upload build-win32 artifact
uses: actions/upload-artifact@v4
with:
name: build-win32-intermediate
path: release/work/build-win32/dist-tar/
path: build-win32/dist/
build-win64:
runs-on: ubuntu-latest
@@ -168,150 +94,27 @@ jobs:
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
mingw-w64 mingw-w64-tools libz-mingw-w64-dev
- name: Build
run: release/build_windows.sh 64
- name: Workaround for old meson version run by Github Actions
run: sed -i 's/^pkg-config/pkgconfig/' cross_win64.txt
# upload-artifact does not preserve permissions
- name: Tar
run: |
cd release/work/build-win64
mkdir dist-tar
cd dist-tar
tar -C .. -cvf dist.tar.gz dist/
- name: Build scrcpy win64
run: make -f release.mk build-win64
- name: Upload artifact
- name: Upload build-win64 artifact
uses: actions/upload-artifact@v4
with:
name: build-win64-intermediate
path: release/work/build-win64/dist-tar/
path: build-win64/dist/
build-macos-aarch64:
runs-on: macos-latest
steps:
- name: Check architecture
run: |
arch=$(uname -m)
if [[ "$arch" != arm64 ]]
then
echo "Unexpected architecture: $arch" >&2
exit 1
fi
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install meson nasm libiconv zlib automake autoconf libtool
- name: Build
env:
# the default Xcode (and macOS SDK) version can be found at
# <https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#xcode>
#
# then the minimal supported deployment target of that macOS SDK can be found at
# <https://developer.apple.com/support/xcode/#minimum-requirements>
MACOSX_DEPLOYMENT_TARGET: 10.13
run: release/build_macos.sh aarch64
# upload-artifact does not preserve permissions
- name: Tar
run: |
cd release/work/build-macos-aarch64
mkdir dist-tar
cd dist-tar
tar -C .. -cvf dist.tar.gz dist/
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-macos-aarch64-intermediate
path: release/work/build-macos-aarch64/dist-tar/
build-macos-x86_64:
runs-on: macos-15-intel
steps:
- name: Check architecture
run: |
arch=$(uname -m)
if [[ "$arch" != x86_64 ]]
then
echo "Unexpected architecture: $arch" >&2
exit 1
fi
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: brew install meson nasm libiconv zlib automake
# autoconf and libtool are already installed on macos-13
- name: Build
env:
# the default Xcode (and macOS SDK) version can be found at
# <https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode>
#
# then the minimal supported deployment target of that macOS SDK can be found at
# <https://developer.apple.com/support/xcode/#minimum-requirements>
MACOSX_DEPLOYMENT_TARGET: 10.13
run: release/build_macos.sh x86_64
# upload-artifact does not preserve permissions
- name: Tar
run: |
cd release/work/build-macos-x86_64
mkdir dist-tar
cd dist-tar
tar -C .. -cvf dist.tar.gz dist/
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-macos-x86_64-intermediate
path: release/work/build-macos-x86_64/dist-tar/
package-linux-x86_64:
needs:
- build-scrcpy-server
- build-linux-x86_64
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download scrcpy-server
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
- name: Download build-linux-x86_64
uses: actions/download-artifact@v4
with:
name: build-linux-x86_64-intermediate
path: release/work/build-linux-x86_64/dist-tar/
# upload-artifact does not preserve permissions
- name: Detar
run: |
cd release/work/build-linux-x86_64
tar xf dist-tar/dist.tar.gz
- name: Package
run: release/package_client.sh linux-x86_64 tar.gz
- name: Upload release
uses: actions/upload-artifact@v4
with:
name: release-linux-x86_64
path: release/output/
package-win32:
package:
needs:
- build-scrcpy-server
- build-win32
- build-win64
runs-on: ubuntu-latest
env:
# $VERSION is used by release.mk
VERSION: ${{ github.event.inputs.name || github.ref_name }}
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -320,194 +123,25 @@ jobs:
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
path: build-server/server/
- name: Download build-win32
uses: actions/download-artifact@v4
with:
name: build-win32-intermediate
path: release/work/build-win32/dist-tar/
# upload-artifact does not preserve permissions
- name: Detar
run: |
cd release/work/build-win32
tar xf dist-tar/dist.tar.gz
- name: Package
run: release/package_client.sh win32 zip
- name: Upload release
uses: actions/upload-artifact@v4
with:
name: release-win32
path: release/output/
package-win64:
needs:
- build-scrcpy-server
- build-win64
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download scrcpy-server
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
path: build-win32/dist/
- name: Download build-win64
uses: actions/download-artifact@v4
with:
name: build-win64-intermediate
path: release/work/build-win64/dist-tar/
# upload-artifact does not preserve permissions
- name: Detar
run: |
cd release/work/build-win64
tar xf dist-tar/dist.tar.gz
path: build-win64/dist/
- name: Package
run: release/package_client.sh win64 zip
- name: Upload release
uses: actions/upload-artifact@v4
with:
name: release-win64
path: release/output
package-macos-aarch64:
needs:
- build-scrcpy-server
- build-macos-aarch64
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download scrcpy-server
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
- name: Download build-macos-aarch64
uses: actions/download-artifact@v4
with:
name: build-macos-aarch64-intermediate
path: release/work/build-macos-aarch64/dist-tar/
# upload-artifact does not preserve permissions
- name: Detar
run: |
cd release/work/build-macos-aarch64
tar xf dist-tar/dist.tar.gz
- name: Package
run: release/package_client.sh macos-aarch64 tar.gz
- name: Upload release
uses: actions/upload-artifact@v4
with:
name: release-macos-aarch64
path: release/output/
package-macos-x86_64:
needs:
- build-scrcpy-server
- build-macos-x86_64
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download scrcpy-server
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
- name: Download build-macos
uses: actions/download-artifact@v4
with:
name: build-macos-x86_64-intermediate
path: release/work/build-macos-x86_64/dist-tar/
# upload-artifact does not preserve permissions
- name: Detar
run: |
cd release/work/build-macos-x86_64
tar xf dist-tar/dist.tar.gz
- name: Package
run: release/package_client.sh macos-x86_64 tar.gz
- name: Upload release
uses: actions/upload-artifact@v4
with:
name: release-macos-x86_64
path: release/output/
release:
needs:
- build-scrcpy-server
- package-linux-x86_64
- package-win32
- package-win64
- package-macos-aarch64
- package-macos-x86_64
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download scrcpy-server
uses: actions/download-artifact@v4
with:
name: scrcpy-server
path: release/work/build-server/server/
- name: Download release-linux-x86_64
uses: actions/download-artifact@v4
with:
name: release-linux-x86_64
path: release/output/
- name: Download release-win32
uses: actions/download-artifact@v4
with:
name: release-win32
path: release/output/
- name: Download release-win64
uses: actions/download-artifact@v4
with:
name: release-win64
path: release/output/
- name: Download release-macos-aarch64
uses: actions/download-artifact@v4
with:
name: release-macos-aarch64
path: release/output/
- name: Download release-macos-x86_64
uses: actions/download-artifact@v4
with:
name: release-macos-x86_64
path: release/output/
- name: Package server
run: release/package_server.sh
- name: Generate checksums
run: release/generate_checksums.sh
run: make -f release.mk package
- name: Upload release artifact
uses: actions/upload-artifact@v4
with:
name: scrcpy-release-${{ env.VERSION }}
path: release/output
path: release-${{ env.VERSION }}

5
FAQ.md
View File

@@ -166,13 +166,14 @@ Rebooting the device is necessary once this option is set.
### Special characters do not work
The default text injection method is limited to ASCII characters. A trick allows
to also inject some [accented characters][accented-characters],
The default text injection method is [limited to ASCII characters][text-input].
A trick allows to also inject some [accented characters][accented-characters],
but that's all. See [#37].
To avoid the problem, [change the keyboard mode to simulate a physical
keyboard][hid].
[text-input]: https://github.com/Genymobile/scrcpy/issues?q=is%3Aopen+is%3Aissue+label%3Aunicode
[accented-characters]: https://blog.rom1v.com/2018/03/introducing-scrcpy/#handle-accented-characters
[#37]: https://github.com/Genymobile/scrcpy/issues/37
[hid]: doc/keyboard.md#physical-keyboard-simulation

View File

@@ -188,7 +188,7 @@
identification within third-party archives.
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2025 Romain Vimont
Copyright (C) 2018-2024 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -2,16 +2,16 @@
source for the project. Do not download releases from random websites, even if
their name contains `scrcpy`.**
# scrcpy (v3.3.4)
# scrcpy (v2.7)
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
_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_.
This application mirrors Android devices (video and audio) connected via
USB or [over TCP/IP](doc/connection.md#tcpip-wireless), and allows to control the
device with the keyboard and the mouse of the computer. It does not require any
_root_ access. It works on _Linux_, _Windows_ and _macOS_.
![screenshot](assets/screenshot-debian-600.jpg)
@@ -58,7 +58,7 @@ Make sure you [enabled USB debugging][enable-adb] on your device(s).
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.
java.lang.SecurityException: 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
@@ -74,20 +74,10 @@ 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))
- [Windows](doc/windows.md)
- [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.
@@ -151,7 +141,7 @@ documented in the following pages:
- [Device](doc/device.md)
- [Window](doc/window.md)
- [Recording](doc/recording.md)
- [Virtual display](doc/virtual_display.md)
- [Virtual display](doc/virtual_displays.md)
- [Tunnels](doc/tunnels.md)
- [OTG](doc/otg.md)
- [Camera](doc/camera.md)
@@ -191,7 +181,6 @@ to your problem immediately.
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)
@@ -207,10 +196,10 @@ work][donate]:
[donate]: https://blog.rom1v.com/about/#support-my-open-source-work
## License
## Licence
Copyright (C) 2018 Genymobile
Copyright (C) 2018-2025 Romain Vimont
Copyright (C) 2018-2024 Romain Vimont
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -2,7 +2,6 @@ _scrcpy() {
local cur prev words cword
local opts="
--always-on-top
--angle
--audio-bit-rate=
--audio-buffer=
--audio-codec=
@@ -18,12 +17,10 @@ _scrcpy() {
--camera-fps=
--camera-high-speed
--camera-size=
--capture-orientation=
--crop=
-d --select-usb
--disable-screensaver
--display-id=
--display-ime-policy=
--display-orientation=
-e --select-tcpip
-f --fullscreen
@@ -40,6 +37,8 @@ _scrcpy() {
--list-cameras
--list-displays
--list-encoders
--lock-video-orientation
--lock-video-orientation=
-m --max-size=
-M
--max-fps=
@@ -58,8 +57,6 @@ _scrcpy() {
--no-mipmaps
--no-mouse-hover
--no-power-on
--no-vd-destroy-content
--no-vd-system-decorations
--no-video
--no-video-playback
--orientation=
@@ -122,7 +119,7 @@ _scrcpy() {
return
;;
--audio-source)
COMPREPLY=($(compgen -W 'output playback mic mic-unprocessed mic-camcorder mic-voice-recognition mic-voice-communication voice-call voice-call-uplink voice-call-downlink voice-performance' -- "$cur"))
COMPREPLY=($(compgen -W 'output mic playback' -- "$cur"))
return
;;
--camera-facing)
@@ -141,22 +138,18 @@ _scrcpy() {
COMPREPLY=($(compgen -W 'disabled uhid aoa' -- "$cur"))
return
;;
--capture-orientation)
COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270 @0 @90 @180 @270 @flip0 @flip90 @flip180 @flip270' -- "$cur"))
return
;;
--orientation|--display-orientation)
COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur"))
return
;;
--display-ime-policy)
COMPREPLY=($(compgen -W 'local fallback hide' -- "$cur"))
return
;;
--record-orientation)
COMPREPLY=($(compgen -W '0 90 180 270' -- "$cur"))
return
;;
--lock-video-orientation)
COMPREPLY=($(compgen -W 'unlocked initial 0 90 180 270' -- "$cur"))
return
;;
--pause-on-exit)
COMPREPLY=($(compgen -W 'true false if-error' -- "$cur"))
return
@@ -201,11 +194,9 @@ _scrcpy() {
|--display-id \
|--max-fps \
|-m|--max-size \
|--new-display \
|-p|--port \
|--push-target \
|--rotation \
|--screen-off-timeout \
|--tunnel-host \
|--tunnel-port \
|--v4l2-buffer \

View File

@@ -1,4 +1,4 @@
#compdef scrcpy scrcpy.exe
#compdef -N scrcpy -N scrcpy.exe
#
# name: scrcpy
# auth: hltdev [hltdev8642@gmail.com]
@@ -9,14 +9,13 @@ local arguments
arguments=(
'--always-on-top[Make scrcpy window always on top \(above other windows\)]'
'--angle=[Rotate the video content by a custom angle, in degrees]'
'--audio-bit-rate=[Encode the audio at the given bit-rate]'
'--audio-buffer=[Configure the audio buffering delay \(in milliseconds\)]'
'--audio-buffer=[Configure the audio buffering delay (in milliseconds)]'
'--audio-codec=[Select the audio codec]:codec:(opus aac flac raw)'
'--audio-codec-options=[Set a list of comma-separated key\:type=value options for the device audio encoder]'
'--audio-dup=[Duplicate audio]'
'--audio-encoder=[Use a specific MediaCodec audio encoder]'
'--audio-source=[Select the audio source]:source:(output playback mic mic-unprocessed mic-camcorder mic-voice-recognition mic-voice-communication voice-call voice-call-uplink voice-call-downlink voice-performance)'
'--audio-source=[Select the audio source]:source:(output mic playback)'
'--audio-output-buffer=[Configure the size of the SDL audio output buffer (in milliseconds)]'
{-b,--video-bit-rate=}'[Encode the video at the given bit-rate]'
'--camera-ar=[Select the camera size by its aspect ratio]'
@@ -25,20 +24,18 @@ arguments=(
'--camera-facing=[Select the device camera by its facing direction]:facing:(front back external)'
'--camera-fps=[Specify the camera capture frame rate]'
'--camera-size=[Specify an explicit camera capture size]'
'--capture-orientation=[Set the capture video orientation]:orientation:(0 90 180 270 flip0 flip90 flip180 flip270 @0 @90 @180 @270 @flip0 @flip90 @flip180 @flip270)'
'--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-id=[Specify the display id to mirror]'
'--display-ime-policy[Set the policy for selecting where the IME should be displayed]'
'--display-orientation=[Set the initial display orientation]:orientation values:(0 90 180 270 flip0 flip90 flip180 flip270)'
{-e,--select-tcpip}'[Use TCP/IP device]'
{-f,--fullscreen}'[Start in fullscreen]'
'--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]'
'-G[Use UHID/AOA gamepad \(same as --gamepad=uhid or --gamepad=aoa, depending on OTG mode\)]'
'-G[Use UHID/AOA gamepad (same as --gamepad=uhid or --gamepad=aoa, depending on OTG mode)]'
'--gamepad=[Set the gamepad input mode]:mode:(disabled uhid aoa)'
{-h,--help}'[Print the help]'
'-K[Use UHID/AOA keyboard \(same as --keyboard=uhid or --keyboard=aoa, depending on OTG mode\)]'
'-K[Use UHID/AOA keyboard (same as --keyboard=uhid or --keyboard=aoa, depending on OTG mode)]'
'--keyboard=[Set the keyboard input mode]:mode:(disabled sdk uhid aoa)'
'--kill-adb-on-close[Kill adb when scrcpy terminates]'
'--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]'
@@ -47,8 +44,9 @@ arguments=(
'--list-cameras[List cameras available on the device]'
'--list-displays[List displays available on the device]'
'--list-encoders[List video and audio encoders available on the device]'
'--lock-video-orientation=[Lock video orientation]:orientation:(unlocked initial 0 90 180 270)'
{-m,--max-size=}'[Limit both the width and height of the video to value]'
'-M[Use UHID/AOA mouse \(same as --mouse=uhid or --mouse=aoa, depending on OTG mode\)]'
'-M[Use UHID/AOA mouse (same as --mouse=uhid or --mouse=aoa, depending on OTG mode)]'
'--max-fps=[Limit the frame rate of screen capture]'
'--mouse=[Set the mouse input mode]:mode:(disabled sdk uhid aoa)'
'--mouse-bind=[Configure bindings of secondary clicks]'
@@ -64,8 +62,6 @@ arguments=(
'--no-mipmaps[Disable the generation of mipmaps]'
'--no-mouse-hover[Do not forward mouse hover events]'
'--no-power-on[Do not power on the device on start]'
'--no-vd-destroy-content[Disable virtual display "destroy content on removal" flag]'
'--no-vd-system-decorations[Disable virtual display system decorations flag]'
'--no-video[Disable video forwarding]'
'--no-video-playback[Disable video playback]'
'--orientation=[Set the video orientation]:orientation values:(0 90 180 270 flip0 flip90 flip180 flip270)'

View File

@@ -1,76 +0,0 @@
# This file is intended to be sourced by other scripts, not executed
process_args() {
if [[ $# != 3 ]]
then
# <host>: linux, macos, win32 or win64
# <build_type>: native or cross
# <link_type>: static or shared
echo "Syntax: $0 <host> <build_type> <link_type>" >&2
exit 1
fi
HOST="$1"
BUILD_TYPE="$2"
LINK_TYPE="$3"
DIRNAME="$HOST-$BUILD_TYPE-$LINK_TYPE"
if [[ "$BUILD_TYPE" != native && "$BUILD_TYPE" != cross ]]
then
echo "Unsupported build type (expected native or cross): $BUILD_TYPE" >&2
exit 1
fi
if [[ "$LINK_TYPE" != static && "$LINK_TYPE" != shared ]]
then
echo "Unsupported link type (expected static or shared): $LINK_TYPE" >&2
exit 1
fi
if [[ "$BUILD_TYPE" == cross ]]
then
if [[ "$HOST" = win32 ]]
then
HOST_TRIPLET=i686-w64-mingw32
elif [[ "$HOST" = win64 ]]
then
HOST_TRIPLET=x86_64-w64-mingw32
else
echo "Unsupported cross-build to host: $HOST" >&2
exit 1
fi
fi
}
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
PATCHES_DIR="$PWD/patches"
WORK_DIR="$PWD/work"
SOURCES_DIR="$WORK_DIR/sources"
BUILD_DIR="$WORK_DIR/build"
INSTALL_DIR="$WORK_DIR/install"
mkdir -p "$INSTALL_DIR" "$SOURCES_DIR" "$WORK_DIR"
checksum() {
local file="$1"
local sum="$2"
echo "$file: verifying checksum..."
echo "$sum $file" | shasum -a256 -c
}
get_file() {
local url="$1"
local file="$2"
local sum="$3"
if [[ -f "$file" ]]
then
echo "$file: found"
else
echo "$file: not found, downloading..."
wget "$url" -O "$file"
fi
checksum "$file" "$sum"
}

32
app/deps/adb.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -ex
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
. common
VERSION=35.0.0
FILENAME=platform-tools_r$VERSION-windows.zip
PROJECT_DIR=platform-tools-$VERSION
SHA256SUM=7ab78a8f8b305ae4d0de647d99c43599744de61a0838d3a47bda0cdffefee87e
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "https://dl.google.com/android/repository/$FILENAME" "$FILENAME" "$SHA256SUM"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
ZIP_PREFIX=platform-tools
unzip "../$FILENAME" \
"$ZIP_PREFIX"/AdbWinApi.dll \
"$ZIP_PREFIX"/AdbWinUsbApi.dll \
"$ZIP_PREFIX"/adb.exe
mv "$ZIP_PREFIX"/* .
rmdir "$ZIP_PREFIX"
fi
mkdir -p "$INSTALL_DIR/$HOST/bin"
cd "$INSTALL_DIR/$HOST/bin"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/$HOST/bin/"

View File

@@ -1,29 +0,0 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-linux.zip"
SHA256SUM=0ead642c943ffe79701fccca8f5f1c69c4ce4f43df2eefee553f6ccb27cbfbe8
PROJECT_DIR="platform-tools-$VERSION-linux"
FILENAME="$PROJECT_DIR.zip"
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
ZIP_PREFIX=platform-tools
unzip "../$FILENAME" "$ZIP_PREFIX"/adb
mv "$ZIP_PREFIX"/* .
rmdir "$ZIP_PREFIX"
fi
mkdir -p "$INSTALL_DIR/adb-linux"
cd "$INSTALL_DIR/adb-linux"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-linux/"

View File

@@ -1,29 +0,0 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-darwin.zip"
SHA256SUM=d3e9fa1df3345cf728586908426615a60863d2632f73f1ce14f0f1349ef000fd
PROJECT_DIR="platform-tools-$VERSION-darwin"
FILENAME="$PROJECT_DIR.zip"
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
ZIP_PREFIX=platform-tools
unzip "../$FILENAME" "$ZIP_PREFIX"/adb
mv "$ZIP_PREFIX"/* .
rmdir "$ZIP_PREFIX"
fi
mkdir -p "$INSTALL_DIR/adb-macos"
cd "$INSTALL_DIR/adb-macos"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-macos/"

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init "$@"
VERSION=36.0.0
URL="https://dl.google.com/android/repository/platform-tools_r$VERSION-win.zip"
SHA256SUM=12c2841f354e92a0eb2fd7bf6f0f9bf8538abce7bd6b060ac8349d6f6a61107c
PROJECT_DIR="platform-tools-$VERSION-windows"
FILENAME="$PROJECT_DIR.zip"
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
ZIP_PREFIX=platform-tools
unzip "../$FILENAME" \
"$ZIP_PREFIX"/AdbWinApi.dll \
"$ZIP_PREFIX"/AdbWinUsbApi.dll \
"$ZIP_PREFIX"/adb.exe
mv "$ZIP_PREFIX"/* .
rmdir "$ZIP_PREFIX"
fi
mkdir -p "$INSTALL_DIR/adb-windows"
cd "$INSTALL_DIR/adb-windows"
cp -r "$SOURCES_DIR/$PROJECT_DIR"/. "$INSTALL_DIR/adb-windows/"

55
app/deps/common Normal file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# This file is intended to be sourced by other scripts, not executed
if [[ $# != 1 ]]
then
# <host>: win32 or win64
echo "Syntax: $0 <host>" >&2
exit 1
fi
HOST="$1"
if [[ "$HOST" = win32 ]]
then
HOST_TRIPLET=i686-w64-mingw32
elif [[ "$HOST" = win64 ]]
then
HOST_TRIPLET=x86_64-w64-mingw32
else
echo "Unsupported host: $HOST" >&2
exit 1
fi
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
PATCHES_DIR="$PWD/patches"
WORK_DIR="$PWD/work"
SOURCES_DIR="$WORK_DIR/sources"
BUILD_DIR="$WORK_DIR/build"
INSTALL_DIR="$WORK_DIR/install"
mkdir -p "$INSTALL_DIR" "$SOURCES_DIR" "$WORK_DIR"
checksum() {
local file="$1"
local sum="$2"
echo "$file: verifying checksum..."
echo "$sum $file" | sha256sum -c
}
get_file() {
local url="$1"
local file="$2"
local sum="$3"
if [[ -f "$file" ]]
then
echo "$file: found"
else
echo "$file: not found, downloading..."
wget "$url" -O "$file"
fi
checksum "$file" "$sum"
}

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"
VERSION=1.5.0
URL="https://code.videolan.org/videolan/dav1d/-/archive/$VERSION/dav1d-$VERSION.tar.gz"
SHA256SUM=78b15d9954b513ea92d27f39362535ded2243e1b0924fde39f37a31ebed5f76b
PROJECT_DIR="dav1d-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"
cd "$SOURCES_DIR"
if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
fi
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"
if [[ -d "$DIRNAME" ]]
then
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
else
mkdir "$DIRNAME"
cd "$DIRNAME"
conf=(
--prefix="$INSTALL_DIR/$DIRNAME"
--libdir=lib
-Denable_tests=false
-Denable_tools=false
# Always build dav1d statically
--default-library=static
)
if [[ "$BUILD_TYPE" == cross ]]
then
case "$HOST" in
win32)
conf+=(
--cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/i686-w64-mingw32.meson"
)
;;
win64)
conf+=(
--cross-file="$SOURCES_DIR/$PROJECT_DIR/package/crossfiles/x86_64-w64-mingw32.meson"
)
;;
*)
echo "Unsupported host: $HOST" >&2
exit 1
esac
fi
meson setup . "$SOURCES_DIR/$PROJECT_DIR" "${conf[@]}"
fi
ninja
ninja install

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
. common
VERSION=7.1.1
URL="https://ffmpeg.org/releases/ffmpeg-$VERSION.tar.xz"
SHA256SUM=733984395e0dbbe5c046abda2dc49a5544e7e0e1e2366bba849222ae9e3a03b1
PROJECT_DIR="ffmpeg-$VERSION"
FILENAME="$PROJECT_DIR.tar.xz"
VERSION=7.0.2
FILENAME=ffmpeg-$VERSION.tar.xz
PROJECT_DIR=ffmpeg-$VERSION
SHA256SUM=8646515b638a3ad303e23af6a3587734447cb8fc0a0c064ecdb8e95c4fd8b389
cd "$SOURCES_DIR"
@@ -16,128 +15,75 @@ if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
get_file "https://ffmpeg.org/releases/$FILENAME" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
fi
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
cd "$BUILD_DIR/$PROJECT_DIR"
if [[ -d "$DIRNAME" ]]
if [[ "$HOST" = win32 ]]
then
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
ARCH=x86
elif [[ "$HOST" = win64 ]]
then
ARCH=x86_64
else
mkdir "$DIRNAME"
cd "$DIRNAME"
echo "Unsupported host: $HOST" >&2
exit 1
fi
if [[ "$HOST" == win* ]]
then
# -static-libgcc to avoid missing libgcc_s_dw2-1.dll
# -static to avoid dynamic dependency to zlib
export CFLAGS='-static-libgcc -static'
export CXXFLAGS="$CFLAGS"
export LDFLAGS='-static-libgcc -static'
elif [[ "$HOST" == "macos" ]]
then
export PKG_CONFIG_PATH="/opt/homebrew/opt/zlib/lib/pkgconfig"
fi
# -static-libgcc to avoid missing libgcc_s_dw2-1.dll
# -static to avoid dynamic dependency to zlib
export CFLAGS='-static-libgcc -static'
export CXXFLAGS="$CFLAGS"
export LDFLAGS='-static-libgcc -static'
export PKG_CONFIG_PATH="$INSTALL_DIR/$DIRNAME/lib/pkgconfig:$PKG_CONFIG_PATH"
if [[ -d "$HOST" ]]
then
echo "'$PWD/$HOST' already exists, not reconfigured"
cd "$HOST"
else
mkdir "$HOST"
cd "$HOST"
conf=(
--prefix="$INSTALL_DIR/$DIRNAME"
--pkg-config-flags="--static"
--extra-cflags="-O2 -fPIC"
--disable-programs
--disable-doc
--disable-swscale
--disable-postproc
--disable-avfilter
--disable-network
--disable-everything
"$SOURCES_DIR/$PROJECT_DIR"/configure \
--prefix="$INSTALL_DIR/$HOST" \
--enable-cross-compile \
--target-os=mingw32 \
--arch="$ARCH" \
--cross-prefix="${HOST_TRIPLET}-" \
--cc="${HOST_TRIPLET}-gcc" \
--extra-cflags="-O2 -fPIC" \
--enable-shared \
--disable-static \
--disable-programs \
--disable-doc \
--disable-swscale \
--disable-postproc \
--disable-avfilter \
--disable-avdevice \
--disable-network \
--disable-everything \
--enable-swresample \
--enable-decoder=h264 \
--enable-decoder=hevc \
--enable-decoder=av1 \
--enable-decoder=pcm_s16le \
--enable-decoder=opus \
--enable-decoder=aac \
--enable-decoder=flac \
--enable-decoder=png \
--enable-protocol=file \
--enable-demuxer=image2 \
--enable-parser=png \
--enable-zlib \
--enable-muxer=matroska \
--enable-muxer=mp4 \
--enable-muxer=opus \
--enable-muxer=flac \
--enable-muxer=wav \
--disable-vulkan
--disable-vaapi
--disable-vdpau
--enable-swresample
--enable-libdav1d
--enable-decoder=h264
--enable-decoder=hevc
--enable-decoder=av1
--enable-decoder=libdav1d
--enable-decoder=pcm_s16le
--enable-decoder=opus
--enable-decoder=aac
--enable-decoder=flac
--enable-decoder=png
--enable-protocol=file
--enable-demuxer=image2
--enable-parser=png
--enable-zlib
--enable-muxer=matroska
--enable-muxer=mp4
--enable-muxer=opus
--enable-muxer=flac
--enable-muxer=wav
)
if [[ "$HOST" == linux ]]
then
conf+=(
--enable-libv4l2
--enable-outdev=v4l2
--enable-encoder=rawvideo
)
else
# libavdevice is only used for V4L2 on Linux
conf+=(
--disable-avdevice
)
fi
if [[ "$LINK_TYPE" == static ]]
then
conf+=(
--enable-static
--disable-shared
)
else
conf+=(
--disable-static
--enable-shared
)
fi
if [[ "$BUILD_TYPE" == cross ]]
then
conf+=(
--enable-cross-compile
--cross-prefix="${HOST_TRIPLET}-"
--cc="${HOST_TRIPLET}-gcc"
)
case "$HOST" in
win32)
conf+=(
--target-os=mingw32
--arch=x86
)
;;
win64)
conf+=(
--target-os=mingw32
--arch=x86_64
)
;;
*)
echo "Unsupported host: $HOST" >&2
exit 1
esac
fi
"$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
fi
make -j

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
. common
VERSION=1.0.29
URL="https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz"
SHA256SUM=7c2dd39c0b2589236e48c93247c986ae272e27570942b4163cb00a060fcf1b74
PROJECT_DIR="libusb-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"
VERSION=1.0.27
FILENAME=libusb-$VERSION.tar.gz
PROJECT_DIR=libusb-$VERSION
SHA256SUM=e8f18a7a36ecbb11fb820bd71540350d8f61bcd9db0d2e8c18a6fb80b214a3de
cd "$SOURCES_DIR"
@@ -16,7 +15,7 @@ if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
get_file "https://github.com/libusb/libusb/archive/refs/tags/v$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
fi
@@ -26,40 +25,20 @@ cd "$BUILD_DIR/$PROJECT_DIR"
export CFLAGS='-O2'
export CXXFLAGS="$CFLAGS"
if [[ -d "$DIRNAME" ]]
if [[ -d "$HOST" ]]
then
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
echo "'$PWD/$HOST' already exists, not reconfigured"
cd "$HOST"
else
mkdir "$DIRNAME"
cd "$DIRNAME"
conf=(
--prefix="$INSTALL_DIR/$DIRNAME"
)
if [[ "$LINK_TYPE" == static ]]
then
conf+=(
--enable-static
--disable-shared
)
else
conf+=(
--disable-static
--enable-shared
)
fi
if [[ "$BUILD_TYPE" == cross ]]
then
conf+=(
--host="$HOST_TRIPLET"
)
fi
mkdir "$HOST"
cd "$HOST"
"$SOURCES_DIR/$PROJECT_DIR"/bootstrap.sh
"$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
"$SOURCES_DIR/$PROJECT_DIR"/configure \
--prefix="$INSTALL_DIR/$HOST" \
--host="$HOST_TRIPLET" \
--enable-shared \
--disable-static
fi
make -j

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env bash
set -ex
. $(dirname ${BASH_SOURCE[0]})/_init
process_args "$@"
DEPS_DIR=$(dirname ${BASH_SOURCE[0]})
cd "$DEPS_DIR"
. common
VERSION=2.32.8
URL="https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz"
SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c
PROJECT_DIR="sdl-$VERSION"
FILENAME="$PROJECT_DIR.tar.gz"
VERSION=2.30.7
FILENAME=SDL-$VERSION.tar.gz
PROJECT_DIR=SDL-release-$VERSION
SHA256SUM=1578c96f62c9ae36b64e431b2aa0e0b0fd07c275dedbc694afc38e19056688f5
cd "$SOURCES_DIR"
@@ -16,9 +15,8 @@ if [[ -d "$PROJECT_DIR" ]]
then
echo "$PWD/$PROJECT_DIR" found
else
get_file "$URL" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "SDL-release-$VERSION"
mv "SDL-release-$VERSION" "$PROJECT_DIR"
get_file "https://github.com/libsdl-org/SDL/archive/refs/tags/release-$VERSION.tar.gz" "$FILENAME" "$SHA256SUM"
tar xf "$FILENAME" # First level directory is "$PROJECT_DIR"
fi
mkdir -p "$BUILD_DIR/$PROJECT_DIR"
@@ -27,54 +25,23 @@ cd "$BUILD_DIR/$PROJECT_DIR"
export CFLAGS='-O2'
export CXXFLAGS="$CFLAGS"
if [[ -d "$DIRNAME" ]]
if [[ -d "$HOST" ]]
then
echo "'$PWD/$DIRNAME' already exists, not reconfigured"
cd "$DIRNAME"
echo "'$PWD/$HOST' already exists, not reconfigured"
cd "$HOST"
else
mkdir "$DIRNAME"
cd "$DIRNAME"
mkdir "$HOST"
cd "$HOST"
conf=(
--prefix="$INSTALL_DIR/$DIRNAME"
)
if [[ "$HOST" == linux ]]
then
conf+=(
--enable-video-wayland
--enable-video-x11
)
fi
if [[ "$LINK_TYPE" == static ]]
then
conf+=(
--enable-static
--disable-shared
)
else
conf+=(
--disable-static
--enable-shared
)
fi
if [[ "$BUILD_TYPE" == cross ]]
then
conf+=(
--host="$HOST_TRIPLET"
)
fi
"$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}"
"$SOURCES_DIR/$PROJECT_DIR"/configure \
--prefix="$INSTALL_DIR/$HOST" \
--host="$HOST_TRIPLET" \
--enable-shared \
--disable-static
fi
make -j
# There is no "make install-strip"
make install
# Strip manually
if [[ "$LINK_TYPE" == shared && "$HOST" == win* ]]
then
${HOST_TRIPLET}-strip "$INSTALL_DIR/$DIRNAME/bin/SDL2.dll"
fi
${HOST_TRIPLET}-strip "$INSTALL_DIR/$HOST/bin/SDL2.dll"

View File

@@ -46,7 +46,6 @@ src = [
'src/util/acksync.c',
'src/util/audiobuf.c',
'src/util/average.c',
'src/util/env.c',
'src/util/file.c',
'src/util/intmap.c',
'src/util/intr.c',
@@ -110,22 +109,20 @@ endif
cc = meson.get_compiler('c')
static = get_option('static')
dependencies = [
dependency('libavformat', version: '>= 57.33', static: static),
dependency('libavcodec', version: '>= 57.37', static: static),
dependency('libavutil', static: static),
dependency('libswresample', static: static),
dependency('sdl2', version: '>= 2.0.5', static: static),
dependency('libavformat', version: '>= 57.33'),
dependency('libavcodec', version: '>= 57.37'),
dependency('libavutil'),
dependency('libswresample'),
dependency('sdl2', version: '>= 2.0.5'),
]
if v4l2_support
dependencies += dependency('libavdevice', static: static)
dependencies += dependency('libavdevice')
endif
if usb_support
dependencies += dependency('libusb-1.0', static: static)
dependencies += dependency('libusb-1.0')
endif
if host_machine.system() == 'windows'
@@ -192,19 +189,19 @@ datadir = get_option('datadir') # by default 'share'
install_man('scrcpy.1')
install_data('data/icon.png',
rename: 'scrcpy.png',
install_dir: datadir / 'icons/hicolor/256x256/apps')
install_dir: join_paths(datadir, 'icons/hicolor/256x256/apps'))
install_data('data/zsh-completion/_scrcpy',
install_dir: datadir / 'zsh/site-functions')
install_dir: join_paths(datadir, 'zsh/site-functions'))
install_data('data/bash-completion/scrcpy',
install_dir: datadir / 'bash-completion/completions')
install_dir: join_paths(datadir, 'bash-completion/completions'))
# Desktop entry file for application launchers
if host_machine.system() == 'linux'
# Install a launcher (ex: /usr/local/share/applications/scrcpy.desktop)
install_data('data/scrcpy.desktop',
install_dir: datadir / 'applications')
install_dir: join_paths(datadir, 'applications'))
install_data('data/scrcpy-console.desktop',
install_dir: datadir / 'applications')
install_dir: join_paths(datadir, 'applications'))
endif
@@ -279,9 +276,3 @@ if get_option('buildtype') == 'debug'
test(t[0], exe)
endforeach
endif
if meson.version().version_compare('>= 0.58.0')
devenv = environment()
devenv.set('SCRCPY_ICON_PATH', meson.current_source_dir() / 'data/icon.png')
meson.add_devenv(devenv)
endif

View File

@@ -13,7 +13,7 @@ BEGIN
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
VALUE "OriginalFilename", "scrcpy.exe"
VALUE "ProductName", "scrcpy"
VALUE "ProductVersion", "3.3.4"
VALUE "ProductVersion", "2.7"
END
END
BLOCK "VarFileInfo"

View File

@@ -19,10 +19,6 @@ provides display and control of Android devices connected on USB (or over TCP/IP
.B \-\-always\-on\-top
Make scrcpy window always on top (above other windows).
.TP
.BI "\-\-angle " degrees
Rotate the video content by a custom angle, in degrees (clockwise).
.TP
.BI "\-\-audio\-bit\-rate " value
Encode the audio at the given bit rate, expressed in bits/s. Unit suffixes are supported: '\fBK\fR' (x1000) and '\fBM\fR' (x1000000).
@@ -67,19 +63,13 @@ The available encoders can be listed by \fB\-\-list\-encoders\fR.
.TP
.BI "\-\-audio\-source " source
Select the audio source. Possible values are:
Select the audio source (output, mic or playback).
- "output": forwards the whole audio output, and disables playback on the device.
- "playback": captures the audio playback (Android apps can opt-out, so the whole output is not necessarily captured).
- "mic": captures the microphone.
- "mic-unprocessed": captures the microphone unprocessed (raw) sound.
- "mic-camcorder": captures the microphone tuned for video recording, with the same orientation as the camera if available.
- "mic-voice-recognition": captures the microphone tuned for 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).
- "voice-call": captures voice call.
- "voice-call-uplink": captures voice call uplink only.
- "voice-call-downlink": captures voice call downlink only.
- "voice-performance": captures audio meant to be processed for live performance (karaoke), includes both the microphone and the device playback.
The "output" source forwards the whole audio output, and disables playback on the device.
The "playback" source captures the audio playback (Android apps can opt-out, so the whole output is not necessarily captured).
The "mic" source captures the microphone.
Default is output.
@@ -103,18 +93,6 @@ Select the camera size by its aspect ratio (+/- 10%).
Possible values are "sensor" (use the camera sensor aspect ratio), "\fInum\fR:\fIden\fR" (e.g. "4:3") and "\fIvalue\fR" (e.g. "1.6").
.TP
.BI "\-\-camera\-facing " facing
Select the device camera by its facing direction.
Possible values are "front", "back" and "external".
.TP
.BI "\-\-camera\-fps " fps
Specify the camera capture frame rate.
If not specified, Android's default frame rate (30 fps) is used.
.TP
.B \-\-camera\-high\-speed
Enable high-speed camera capture mode.
@@ -128,26 +106,28 @@ Specify the device camera id to mirror.
The available camera ids can be listed by \fB\-\-list\-cameras\fR.
.TP
.BI "\-\-camera\-size " width\fRx\fIheight
Specify an explicit camera capture size.
.BI "\-\-camera\-facing " facing
Select the device camera by its facing direction.
Possible values are "front", "back" and "external".
.TP
.BI "\-\-capture\-orientation " value
Possible values are 0, 90, 180, 270, flip0, flip90, flip180 and flip270, possibly prefixed by '@'.
.BI "\-\-camera\-fps " fps
Specify the camera capture frame rate.
The number represents the clockwise rotation in degrees; the "flip" keyword applies a horizontal flip before the rotation.
If not specified, Android's default frame rate (30 fps) is used.
If a leading '@' is passed (@90) for display capture, then the rotation is locked, and is relative to the natural device orientation.
If '@' is passed alone, then the rotation is locked to the initial device orientation.
Default is 0.
.TP
.BI "\-\-camera\-size " width\fRx\fIheight
Specify an explicit camera capture size.
.TP
.BI "\-\-crop " width\fR:\fIheight\fR:\fIx\fR:\fIy
Crop the device screen on the server.
The values are expressed in the device natural orientation (typically, portrait for a phone, landscape for a tablet).
The values are expressed in the device natural orientation (typically, portrait for a phone, landscape for a tablet). Any
.B \-\-max\-size
value is computed on the cropped size.
.TP
.B \-d, \-\-select\-usb
@@ -167,19 +147,6 @@ The available display ids can be listed by \fB\-\-list\-displays\fR.
Default is 0.
.TP
.BI "\-\-display\-ime\-policy " value
Set the policy for selecting where the IME should be displayed.
Possible values are "local", "fallback" and "hide":
- "local" means that the IME should appear on the local display.
- "fallback" means that the IME should appear on a fallback display (the default display).
- "hide" means that the IME should be hidden.
By default, the IME policy is left unchanged.
.TP
.BI "\-\-display\-orientation " value
Set the initial display orientation.
@@ -274,6 +241,16 @@ List video and audio encoders available on the device.
.B \-\-list\-displays
List displays available on the device.
.TP
\fB\-\-lock\-video\-orientation\fR[=\fIvalue\fR]
Lock capture video orientation to \fIvalue\fR.
Possible values are "unlocked", "initial" (locked to the initial orientation), 0, 90, 180, and 270. The values represent the clockwise rotation from the natural device orientation, in degrees.
Default is "unlocked".
Passing the option without argument is equivalent to passing "initial".
.TP
.BI "\-m, \-\-max\-size " value
Limit both the width and height of the video to \fIvalue\fR. The other dimension is computed so that the device aspect\-ratio is preserved.
@@ -337,13 +314,14 @@ Disable video and audio playback on the computer (equivalent to \fB\-\-no\-video
.TP
\fB\-\-new\-display\fR[=[\fIwidth\fRx\fIheight\fR][/\fIdpi\fR]]
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI.
Create a new display with the specified resolution and density. If not provided, they default to the main display dimensions and DPI, and \fB\-\-max\-size\fR is considered.
Examples:
\-\-new\-display=1920x1080
\-\-new\-display=1920x1080/420
\-\-new\-display # main display size and density
\-\-new\-display -m1920 # scaled to fit a max size of 1920
\-\-new\-display=/240 # main display size and 240 dpi
.TP
@@ -388,16 +366,6 @@ Do not forward mouse hover (mouse motion without any clicks) events.
.B \-\-no\-power\-on
Do not power on the device on start.
.TP
.B \-\-no\-vd\-destroy\-content
Disable virtual display "destroy content on removal" flag.
With this option, when the virtual display is closed, the running apps are moved to the main display rather than being destroyed.
.TP
.B \-\-no\-vd\-system\-decorations
Disable virtual display system decorations flag.
.TP
.B \-\-no\-video
Disable video forwarding.
@@ -408,7 +376,7 @@ Disable video playback on the computer.
.TP
.B \-\-no\-window
Disable scrcpy window. Implies --no-video-playback.
Disable scrcpy window. Implies --no-video-playback and --no-control.
.TP
.BI "\-\-orientation " value
@@ -510,10 +478,6 @@ The device serial number. Mandatory only if several devices are connected to adb
.B \-S, \-\-turn\-screen\-off
Turn the device screen off immediately.
.TP
.B "\-\-screen\-off\-timeout " seconds
Set the screen off timeout while scrcpy is running (restore the initial value on exit).
.TP
.BI "\-\-shortcut\-mod " key\fR[+...]][,...]
Specify the modifiers to use for scrcpy shortcuts. Possible keys are "lctrl", "rctrl", "lalt", "ralt", "lsuper" and "rsuper".
@@ -547,15 +511,13 @@ Enable "show touches" on start, restore the initial value on exit.
It only shows physical touches (not clicks from scrcpy).
.TP
.BI "\-\-tcpip\fR[=[+]\fIip\fR[:\fIport\fR]]
Configure and connect the device over TCP/IP.
.BI "\-\-tcpip\fR[=\fIip\fR[:\fIport\fR]]
Configure and reconnect the device over TCP/IP.
If a destination address is provided, then scrcpy connects to this address before starting. The device must listen on the given TCP port (default is 5555).
If no destination address is provided, then scrcpy attempts to find the IP address and adb port of the current device (typically connected over USB), enables TCP/IP mode if necessary, then connects to this address before starting.
Prefix the address with a '+' to force a reconnection.
.TP
.BI "\-\-time\-limit " seconds
Set the maximum mirroring time, in seconds.
@@ -586,6 +548,8 @@ Default is "info" for release builds, "debug" for debug builds.
.BI "\-\-v4l2-sink " /dev/videoN
Output to v4l2loopback device.
It requires to lock the video orientation (see \fB\-\-lock\-video\-orientation\fR).
.TP
.BI "\-\-v4l2-buffer " ms
Add a buffering delay (in milliseconds) before pushing frames. This increases latency to compensate for jitter.
@@ -852,7 +816,7 @@ Report bugs to <https://github.com/Genymobile/scrcpy/issues>.
.SH COPYRIGHT
Copyright \(co 2018 Genymobile <https://www.genymobile.com>
Copyright \(co 2018\-2025 Romain Vimont <rom@rom1v.com>
Copyright \(co 2018\-2024 Romain Vimont <rom@rom1v.com>
Licensed under the Apache License, Version 2.0.

View File

@@ -4,11 +4,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "adb/adb_device.h"
#include "adb/adb_parser.h"
#include "util/env.h"
#include "adb_device.h"
#include "adb_parser.h"
#include "util/file.h"
#include "util/log.h"
#include "util/process_intr.h"
@@ -26,45 +24,15 @@
*/
#define SC_ADB_COMMAND(...) { sc_adb_get_executable(), __VA_ARGS__, NULL }
static char *adb_executable;
bool
sc_adb_init(void) {
adb_executable = sc_get_env("ADB");
if (adb_executable) {
LOGD("Using adb: %s", adb_executable);
return true;
}
#if !defined(PORTABLE) || defined(_WIN32)
adb_executable = strdup("adb");
if (!adb_executable) {
LOG_OOM();
return false;
}
#else
// For portable builds, use the absolute path to the adb executable
// in the same directory as scrcpy (except on Windows, where "adb"
// is sufficient)
adb_executable = sc_file_get_local_path("adb");
if (!adb_executable) {
// Error already logged
return false;
}
LOGD("Using adb (portable): %s", adb_executable);
#endif
return true;
}
void
sc_adb_destroy(void) {
free(adb_executable);
}
static const char *adb_executable;
const char *
sc_adb_get_executable(void) {
if (!adb_executable) {
adb_executable = getenv("ADB");
if (!adb_executable)
adb_executable = "adb";
}
return adb_executable;
}
@@ -103,14 +71,14 @@ argv_to_string(const char *const *argv, char *buf, size_t bufsize) {
static void
show_adb_installation_msg(void) {
#ifndef _WIN32
#ifndef __WINDOWS__
static const struct {
const char *binary;
const char *command;
} pkg_managers[] = {
{"apt", "apt install adb"},
{"apt-get", "apt-get install adb"},
{"brew", "brew install --cask android-platform-tools"},
{"brew", "brew cask install android-platform-tools"},
{"dnf", "dnf install android-tools"},
{"emerge", "emerge dev-util/android-tools"},
{"pacman", "pacman -S android-tools"},
@@ -331,7 +299,7 @@ sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
bool
sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
const char *remote, unsigned flags) {
#ifdef _WIN32
#ifdef __WINDOWS__
// Windows will parse the string, so the paths must be quoted
// (see sys/win/command.c)
local = sc_str_quote(local);
@@ -351,7 +319,7 @@ sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
sc_pid pid = sc_adb_execute(argv, flags);
#ifdef _WIN32
#ifdef __WINDOWS__
free((void *) remote);
free((void *) local);
#endif
@@ -362,7 +330,7 @@ sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
bool
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
unsigned flags) {
#ifdef _WIN32
#ifdef __WINDOWS__
// Windows will parse the string, so the local name must be quoted
// (see sys/win/command.c)
local = sc_str_quote(local);
@@ -377,7 +345,7 @@ sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
sc_pid pid = sc_adb_execute(argv, flags);
#ifdef _WIN32
#ifdef __WINDOWS__
free((void *) local);
#endif
@@ -413,7 +381,7 @@ sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags) {
// "adb connect" always returns successfully (with exit code 0), even in
// case of failure. As a workaround, check if its output starts with
// "connected" or "already connected".
// "connected".
char buf[128];
ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
sc_pipe_close(pout);
@@ -430,8 +398,7 @@ sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags) {
assert((size_t) r < sizeof(buf));
buf[r] = '\0';
ok = !strncmp("connected", buf, sizeof("connected") - 1)
|| !strncmp("already connected", buf, sizeof("already connected") - 1);
ok = !strncmp("connected", buf, sizeof("connected") - 1);
if (!ok && !(flags & SC_ADB_NO_STDERR)) {
// "adb connect" also prints errors to stdout. Since we capture it,
// re-print the error to stderr.
@@ -772,21 +739,3 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
return sc_adb_parse_device_ip(buf);
}
uint16_t
sc_adb_get_device_sdk_version(struct sc_intr *intr, const char *serial) {
char *sdk_version =
sc_adb_getprop(intr, serial, "ro.build.version.sdk", SC_ADB_SILENT);
if (!sdk_version) {
return 0;
}
long value;
bool ok = sc_str_parse_integer(sdk_version, &value);
free(sdk_version);
if (!ok || value < 0 || value > 0xFFFF) {
return 0;
}
return value;
}

View File

@@ -6,7 +6,7 @@
#include <stdbool.h>
#include <inttypes.h>
#include "adb/adb_device.h"
#include "adb_device.h"
#include "util/intr.h"
#define SC_ADB_NO_STDOUT (1 << 0)
@@ -15,12 +15,6 @@
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)
bool
sc_adb_init(void);
void
sc_adb_destroy(void);
const char *
sc_adb_get_executable(void);
@@ -120,10 +114,4 @@ sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);
/**
* Return the device SDK version.
*/
uint16_t
sc_adb_get_device_sdk_version(struct sc_intr *intr, const char *serial);
#endif

View File

@@ -4,6 +4,7 @@
#include "common.h"
#include <stdbool.h>
#include <stddef.h>
#include "util/vector.h"

View File

@@ -3,7 +3,6 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "util/log.h"
#include "util/str.h"

View File

@@ -3,9 +3,9 @@
#include "common.h"
#include <stdbool.h>
#include <stddef.h>
#include "adb/adb_device.h"
#include "adb_device.h"
/**
* Parse the available devices from the output of `adb devices`

View File

@@ -1,11 +1,11 @@
#include "adb_tunnel.h"
#include <assert.h>
#include <inttypes.h>
#include "adb/adb.h"
#include "adb.h"
#include "util/log.h"
#include "util/net_intr.h"
#include "util/process_intr.h"
static bool
listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {

View File

@@ -3,7 +3,9 @@
#include "common.h"
#include <SDL2/SDL_audio.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include "audio_regulator.h"
#include "trait/frame_sink.h"

View File

@@ -1,9 +1,5 @@
#include "audio_regulator.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
@@ -76,10 +72,8 @@ sc_audio_regulator_pull(struct sc_audio_regulator *ar, uint8_t *out,
// Wait until the buffer is filled up to at least target_buffering
// before playing
if (buffered_samples < ar->target_buffering) {
#ifdef SC_AUDIO_REGULATOR_DEBUG
LOGD("[Audio] Inserting initial buffering silence: %" PRIu32
LOGV("[Audio] Inserting initial buffering silence: %" PRIu32
" samples", out_samples);
#endif
// Delay playback starting to reach the target buffering. Fill the
// whole buffer with silence (len is small compared to the
// arbitrary margin value).
@@ -100,10 +94,8 @@ sc_audio_regulator_pull(struct sc_audio_regulator *ar, uint8_t *out,
// dropped to keep the latency minimal. However, this would cause very
// audible glitches, so let the clock compensation restore the target
// latency.
#ifdef SC_AUDIO_REGULATOR_DEBUG
LOGD("[Audio] Buffer underflow, inserting silence: %" PRIu32 " samples",
silence);
#endif
memset(out + TO_BYTES(read), 0, TO_BYTES(silence));
bool received = atomic_load_explicit(&ar->received,
@@ -141,36 +133,6 @@ bool
sc_audio_regulator_push(struct sc_audio_regulator *ar, const AVFrame *frame) {
SwrContext *swr_ctx = ar->swr_ctx;
uint32_t input_samples = frame->nb_samples;
assert(frame->pts >= 0);
int64_t pts = frame->pts;
if (ar->next_expected_pts && pts - ar->next_expected_pts > 100000) {
LOGV("[Audio] Discontinuity detected: %" PRIi64 "µs",
pts - ar->next_expected_pts);
// More than 100ms: consider it as a discontinuity
// (typically because silence packets were not captured)
uint32_t can_read = sc_audiobuf_can_read(&ar->buf);
if (input_samples + can_read < ar->target_buffering) {
// Adjust buffering to the target value directly
uint32_t silence = ar->target_buffering - can_read - input_samples;
sc_audiobuf_write_silence(&ar->buf, silence);
}
// Reset state
ar->avg_buffering.avg = ar->target_buffering;
int ret = swr_set_compensation(swr_ctx, 0, 0);
(void) ret;
assert(!ret); // disabling compensation should never fail
ar->compensation_active = false;
ar->samples_since_resync = 0;
atomic_store_explicit(&ar->underflow, 0, memory_order_relaxed);
}
int64_t packet_duration = input_samples * INT64_C(1000000)
/ ar->sample_rate;
ar->next_expected_pts = pts + packet_duration;
int64_t swr_delay = swr_get_delay(swr_ctx, ar->sample_rate);
// No need to av_rescale_rnd(), input and output sample rates are the same.
// Add more space (256) for clock compensation.
@@ -243,7 +205,6 @@ sc_audio_regulator_push(struct sc_audio_regulator *ar, const AVFrame *frame) {
if (played) {
underflow = atomic_exchange_explicit(&ar->underflow, 0,
memory_order_relaxed);
ar->underflow_report += underflow;
max_buffered_samples = ar->target_buffering * 11 / 10
+ 60 * ar->sample_rate / 1000 /* 60 ms */;
@@ -290,7 +251,7 @@ sc_audio_regulator_push(struct sc_audio_regulator *ar, const AVFrame *frame) {
}
// Number of samples added (or removed, if negative) for compensation
int32_t instant_compensation = (int32_t) written - input_samples;
int32_t instant_compensation = (int32_t) written - frame->nb_samples;
// Inserting silence instantly increases buffering
int32_t inserted_silence = (int32_t) underflow;
// Dropping input samples instantly decreases buffering
@@ -346,9 +307,7 @@ sc_audio_regulator_push(struct sc_audio_regulator *ar, const AVFrame *frame) {
int abs_max_diff = distance / 50;
diff = CLAMP(diff, -abs_max_diff, abs_max_diff);
LOGV("[Audio] Buffering: target=%" PRIu32 " avg=%f cur=%" PRIu32
" compensation=%d (underflow=%" PRIu32 ")",
ar->target_buffering, avg, can_read, diff, ar->underflow_report);
ar->underflow_report = 0;
" compensation=%d", ar->target_buffering, avg, can_read, diff);
int ret = swr_set_compensation(swr_ctx, diff, distance);
if (ret < 0) {
@@ -431,9 +390,7 @@ sc_audio_regulator_init(struct sc_audio_regulator *ar, size_t sample_size,
atomic_init(&ar->played, false);
atomic_init(&ar->received, false);
atomic_init(&ar->underflow, 0);
ar->underflow_report = 0;
ar->compensation_active = false;
ar->next_expected_pts = 0;
return true;

View File

@@ -5,8 +5,6 @@
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include "util/audiobuf.h"
@@ -46,9 +44,6 @@ struct sc_audio_regulator {
// Number of silence samples inserted since the last received packet
atomic_uint_least32_t underflow;
// Number of silence samples inserted since the last log
uint32_t underflow_report;
// Non-zero compensation applied (only used by the receiver thread)
bool compensation_active;
@@ -57,9 +52,6 @@ struct sc_audio_regulator {
// Set to true the first time samples are pulled by the player
atomic_bool played;
// PTS of the next expected packet (useful to detect discontinuities)
int64_t next_expected_pts;
};
bool

View File

@@ -5,7 +5,6 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "options.h"
@@ -14,7 +13,6 @@
#include "util/str.h"
#include "util/strbuf.h"
#include "util/term.h"
#include "util/tick.h"
#define STR_IMPL_(x) #x
#define STR(x) STR_IMPL_(x)
@@ -109,11 +107,6 @@ enum {
OPT_LIST_APPS,
OPT_START_APP,
OPT_SCREEN_OFF_TIMEOUT,
OPT_CAPTURE_ORIENTATION,
OPT_ANGLE,
OPT_NO_VD_SYSTEM_DECORATIONS,
OPT_NO_VD_DESTROY_CONTENT,
OPT_DISPLAY_IME_POLICY,
};
struct sc_option {
@@ -155,13 +148,6 @@ static const struct sc_option options[] = {
.longopt = "always-on-top",
.text = "Make scrcpy window always on top (above other windows).",
},
{
.longopt_id = OPT_ANGLE,
.longopt = "angle",
.argdesc = "degrees",
.text = "Rotate the video content by a custom angle, in degrees "
"(clockwise).",
},
{
.longopt_id = OPT_AUDIO_BIT_RATE,
.longopt = "audio-bit-rate",
@@ -217,31 +203,13 @@ static const struct sc_option options[] = {
.longopt_id = OPT_AUDIO_SOURCE,
.longopt = "audio-source",
.argdesc = "source",
.text = "Select the audio source. Possible values are:\n"
" - \"output\": forwards the whole audio output, and disables "
"playback on the device.\n"
" - \"playback\": captures the audio playback (Android apps "
"can opt-out, so the whole output is not necessarily "
.text = "Select the audio source (output, mic or playback).\n"
"The \"output\" source forwards the whole audio output, and "
"disables playback on the device.\n"
"The \"playback\" source captures the audio playback (Android "
"apps can opt-out, so the whole output is not necessarily "
"captured).\n"
" - \"mic\": captures the microphone.\n"
" - \"mic-unprocessed\": captures the microphone unprocessed "
"(raw) sound.\n"
" - \"mic-camcorder\": captures the microphone tuned for video "
"recording, with the same orientation as the camera if "
"available.\n"
" - \"mic-voice-recognition\": captures the microphone tuned "
"for voice recognition.\n"
" - \"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).\n"
" - \"voice-call\": captures voice call.\n"
" - \"voice-call-uplink\": captures voice call uplink only.\n"
" - \"voice-call-downlink\": captures voice call downlink "
"only.\n"
" - \"voice-performance\": captures audio meant to be "
"processed for live performance (karaoke), includes both the "
"microphone and the device playback.\n"
"The \"mic\" source captures the microphone.\n"
"Default is output.",
},
{
@@ -277,6 +245,14 @@ static const struct sc_option options[] = {
"ratio), \"<num>:<den>\" (e.g. \"4:3\") or \"<value>\" (e.g. "
"\"1.6\")."
},
{
.longopt_id = OPT_CAMERA_ID,
.longopt = "camera-id",
.argdesc = "id",
.text = "Specify the device camera id to mirror.\n"
"The available camera ids can be listed by:\n"
" scrcpy --list-cameras",
},
{
.longopt_id = OPT_CAMERA_FACING,
.longopt = "camera-facing",
@@ -284,14 +260,6 @@ static const struct sc_option options[] = {
.text = "Select the device camera by its facing direction.\n"
"Possible values are \"front\", \"back\" and \"external\".",
},
{
.longopt_id = OPT_CAMERA_FPS,
.longopt = "camera-fps",
.argdesc = "value",
.text = "Specify the camera capture frame rate.\n"
"If not specified, Android's default frame rate (30 fps) is "
"used.",
},
{
.longopt_id = OPT_CAMERA_HIGH_SPEED,
.longopt = "camera-high-speed",
@@ -299,14 +267,6 @@ static const struct sc_option options[] = {
"This mode is restricted to specific resolutions and frame "
"rates, listed by --list-camera-sizes.",
},
{
.longopt_id = OPT_CAMERA_ID,
.longopt = "camera-id",
.argdesc = "id",
.text = "Specify the device camera id to mirror.\n"
"The available camera ids can be listed by:\n"
" scrcpy --list-cameras",
},
{
.longopt_id = OPT_CAMERA_SIZE,
.longopt = "camera-size",
@@ -314,21 +274,12 @@ static const struct sc_option options[] = {
.text = "Specify an explicit camera capture size.",
},
{
.longopt_id = OPT_CAPTURE_ORIENTATION,
.longopt = "capture-orientation",
.longopt_id = OPT_CAMERA_FPS,
.longopt = "camera-fps",
.argdesc = "value",
.text = "Set the capture video orientation.\n"
"Possible values are 0, 90, 180, 270, flip0, flip90, flip180 "
"and flip270, possibly prefixed by '@'.\n"
"The number represents the clockwise rotation in degrees; the "
"flip\" keyword applies a horizontal flip before the "
"rotation.\n"
"If a leading '@' is passed (@90) for display capture, then "
"the rotation is locked, and is relative to the natural device "
"orientation.\n"
"If '@' is passed alone, then the rotation is locked to the "
"initial device orientation.\n"
"Default is 0.",
.text = "Specify the camera capture frame rate.\n"
"If not specified, Android's default frame rate (30 fps) is "
"used.",
},
{
// Not really deprecated (--codec has never been released), but without
@@ -351,7 +302,8 @@ static const struct sc_option options[] = {
.argdesc = "width:height:x:y",
.text = "Crop the device screen on the server.\n"
"The values are expressed in the device natural orientation "
"(typically, portrait for a phone, landscape for a tablet).",
"(typically, portrait for a phone, landscape for a tablet). "
"Any --max-size value is computed on the cropped size.",
},
{
.shortopt = 'd',
@@ -385,19 +337,6 @@ static const struct sc_option options[] = {
" scrcpy --list-displays\n"
"Default is 0.",
},
{
.longopt_id = OPT_DISPLAY_IME_POLICY,
.longopt = "display-ime-policy",
.argdesc = "value",
.text = "Set the policy for selecting where the IME should be "
"displayed.\n"
"Possible values are \"local\", \"fallback\" and \"hide\".\n"
"\"local\" means that the IME should appear on the local "
"display.\n"
"\"fallback\" means that the IME should appear on a fallback "
"display (the default display).\n"
"\"hide\" means that the IME should be hidden.",
},
{
.longopt_id = OPT_DISPLAY_ORIENTATION,
.longopt = "display-orientation",
@@ -532,10 +471,18 @@ static const struct sc_option options[] = {
.text = "List video and audio encoders available on the device.",
},
{
// deprecated
.longopt_id = OPT_LOCK_VIDEO_ORIENTATION,
.longopt = "lock-video-orientation",
.argdesc = "value",
.optional_arg = true,
.text = "Lock capture video orientation to value.\n"
"Possible values are \"unlocked\", \"initial\" (locked to the "
"initial orientation), 0, 90, 180 and 270. The values "
"represent the clockwise rotation from the natural device "
"orientation, in degrees.\n"
"Default is \"unlocked\".\n"
"Passing the option without argument is equivalent to passing "
"\"initial\".",
},
{
.shortopt = 'm',
@@ -625,11 +572,12 @@ static const struct sc_option options[] = {
.optional_arg = true,
.text = "Create a new display with the specified resolution and "
"density. If not provided, they default to the main display "
"dimensions and DPI.\n"
"dimensions and DPI, and --max-size is considered.\n"
"Examples:\n"
" --new-display=1920x1080\n"
" --new-display=1920x1080/420 # force 420 dpi\n"
" --new-display # main display size and density\n"
" --new-display -m1920 # scaled to fit a max size of 1920\n"
" --new-display=/240 # main display size and 240 dpi",
},
{
@@ -694,20 +642,6 @@ static const struct sc_option options[] = {
.longopt = "no-power-on",
.text = "Do not power on the device on start.",
},
{
.longopt_id = OPT_NO_VD_DESTROY_CONTENT,
.longopt = "no-vd-destroy-content",
.text = "Disable virtual display \"destroy content on removal\" "
"flag.\n"
"With this option, when the virtual display is closed, the "
"running apps are moved to the main display rather than being "
"destroyed.",
},
{
.longopt_id = OPT_NO_VD_SYSTEM_DECORATIONS,
.longopt = "no-vd-system-decorations",
.text = "Disable virtual display system decorations flag.",
},
{
.longopt_id = OPT_NO_VIDEO,
.longopt = "no-video",
@@ -721,7 +655,8 @@ static const struct sc_option options[] = {
{
.longopt_id = OPT_NO_WINDOW,
.longopt = "no-window",
.text = "Disable scrcpy window. Implies --no-video-playback.",
.text = "Disable scrcpy window. Implies --no-video-playback and "
"--no-control.",
},
{
.longopt_id = OPT_ORIENTATION,
@@ -903,17 +838,16 @@ static const struct sc_option options[] = {
{
.longopt_id = OPT_TCPIP,
.longopt = "tcpip",
.argdesc = "[+]ip[:port]",
.argdesc = "ip[:port]",
.optional_arg = true,
.text = "Configure and connect the device over TCP/IP.\n"
.text = "Configure and reconnect the device over TCP/IP.\n"
"If a destination address is provided, then scrcpy connects to "
"this address before starting. The device must listen on the "
"given TCP port (default is 5555).\n"
"If no destination address is provided, then scrcpy attempts "
"to find the IP address of the current device (typically "
"connected over USB), enables TCP/IP mode, then connects to "
"this address before starting.\n"
"Prefix the address with a '+' to force a reconnection.",
"this address before starting.",
},
{
.longopt_id = OPT_TIME_LIMIT,
@@ -961,6 +895,8 @@ static const struct sc_option options[] = {
.longopt = "v4l2-sink",
.argdesc = "/dev/videoN",
.text = "Output to v4l2loopback device.\n"
"It requires to lock the video orientation (see "
"--lock-video-orientation).\n"
"This feature is only available on Linux.",
},
{
@@ -1647,24 +1583,77 @@ parse_audio_output_buffer(const char *s, sc_tick *tick) {
}
static bool
parse_display_ime_policy(const char *s, enum sc_display_ime_policy *policy) {
if (!strcmp(s, "local")) {
*policy = SC_DISPLAY_IME_POLICY_LOCAL;
parse_lock_video_orientation(const char *s,
enum sc_lock_video_orientation *lock_mode) {
if (!s || !strcmp(s, "initial")) {
// Without argument, lock the initial orientation
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_INITIAL;
return true;
}
if (!strcmp(s, "fallback")) {
*policy = SC_DISPLAY_IME_POLICY_FALLBACK;
if (!strcmp(s, "unlocked")) {
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_UNLOCKED;
return true;
}
if (!strcmp(s, "hide")) {
*policy = SC_DISPLAY_IME_POLICY_HIDE;
if (!strcmp(s, "0")) {
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_0;
return true;
}
LOGE("Unsupported display IME policy: %s (expected local, fallback or "
"hide)", s);
if (!strcmp(s, "90")) {
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_90;
return true;
}
if (!strcmp(s, "180")) {
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_180;
return true;
}
if (!strcmp(s, "270")) {
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_270;
return true;
}
if (!strcmp(s, "1")) {
LOGW("--lock-video-orientation=1 is deprecated, use "
"--lock-video-orientation=270 instead.");
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_270;
return true;
}
if (!strcmp(s, "2")) {
LOGW("--lock-video-orientation=2 is deprecated, use "
"--lock-video-orientation=180 instead.");
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_180;
return true;
}
if (!strcmp(s, "3")) {
LOGW("--lock-video-orientation=3 is deprecated, use "
"--lock-video-orientation=90 instead.");
*lock_mode = SC_LOCK_VIDEO_ORIENTATION_90;
return true;
}
LOGE("Unsupported --lock-video-orientation value: %s (expected initial, "
"unlocked, 0, 90, 180 or 270).", s);
return false;
}
static bool
parse_rotation(const char *s, uint8_t *rotation) {
long value;
bool ok = parse_integer_arg(s, &value, false, 0, 3, "rotation");
if (!ok) {
return false;
}
*rotation = (uint8_t) value;
return true;
}
static bool
parse_orientation(const char *s, enum sc_orientation *orientation) {
if (!strcmp(s, "0")) {
@@ -1704,32 +1693,6 @@ parse_orientation(const char *s, enum sc_orientation *orientation) {
return false;
}
static bool
parse_capture_orientation(const char *s, enum sc_orientation *orientation,
enum sc_orientation_lock *lock) {
if (*s == '\0') {
LOGE("Capture orientation may not be empty (expected 0, 90, 180, 270, "
"flip0, flip90, flip180 or flip270, possibly prefixed by '@')");
return false;
}
// Lock the orientation by a leading '@'
if (s[0] == '@') {
// Consume '@'
++s;
if (*s == '\0') {
// Only '@': lock to the initial orientation (orientation is unused)
*lock = SC_ORIENTATION_LOCKED_INITIAL;
return true;
}
*lock = SC_ORIENTATION_LOCKED_VALUE;
} else {
*lock = SC_ORIENTATION_UNLOCKED;
}
return parse_orientation(s, orientation);
}
static bool
parse_window_position(const char *s, int16_t *position) {
// special value for "auto"
@@ -2054,50 +2017,8 @@ parse_audio_source(const char *optarg, enum sc_audio_source *source) {
return true;
}
if (!strcmp(optarg, "mic-unprocessed")) {
*source = SC_AUDIO_SOURCE_MIC_UNPROCESSED;
return true;
}
if (!strcmp(optarg, "mic-camcorder")) {
*source = SC_AUDIO_SOURCE_MIC_CAMCORDER;
return true;
}
if (!strcmp(optarg, "mic-voice-recognition")) {
*source = SC_AUDIO_SOURCE_MIC_VOICE_RECOGNITION;
return true;
}
if (!strcmp(optarg, "mic-voice-communication")) {
*source = SC_AUDIO_SOURCE_MIC_VOICE_COMMUNICATION;
return true;
}
if (!strcmp(optarg, "voice-call")) {
*source = SC_AUDIO_SOURCE_VOICE_CALL;
return true;
}
if (!strcmp(optarg, "voice-call-uplink")) {
*source = SC_AUDIO_SOURCE_VOICE_CALL_UPLINK;
return true;
}
if (!strcmp(optarg, "voice-call-downlink")) {
*source = SC_AUDIO_SOURCE_VOICE_CALL_DOWNLINK;
return true;
}
if (!strcmp(optarg, "voice-performance")) {
*source = SC_AUDIO_SOURCE_VOICE_PERFORMANCE;
return true;
}
LOGE("Unsupported audio source: %s (expected output, mic, playback, "
"mic-unprocessed, mic-camcorder, mic-voice-recognition, "
"mic-voice-communication, voice-call, voice-call-uplink, "
"voice-call-downlink, voice-performance)", optarg);
LOGE("Unsupported audio source: %s (expected output, mic or playback)",
optarg);
return false;
}
@@ -2381,8 +2302,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->crop = optarg;
break;
case OPT_DISPLAY:
LOGE("--display has been removed, use --display-id instead.");
return false;
LOGW("--display is deprecated, use --display-id instead.");
// fall through
case OPT_DISPLAY_ID:
if (!parse_display_id(optarg, &opts->display_id)) {
return false;
@@ -2446,13 +2367,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
"--mouse=uhid instead.");
return false;
case OPT_LOCK_VIDEO_ORIENTATION:
LOGE("--lock-video-orientation has been removed, use "
"--capture-orientation instead.");
return false;
case OPT_CAPTURE_ORIENTATION:
if (!parse_capture_orientation(optarg,
&opts->capture_orientation,
&opts->capture_orientation_lock)) {
if (!parse_lock_video_orientation(optarg,
&opts->lock_video_orientation)) {
return false;
}
break;
@@ -2470,9 +2386,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->control = false;
break;
case OPT_NO_DISPLAY:
LOGE("--no-display has been removed, use --no-playback "
"instead.");
return false;
LOGW("--no-display is deprecated, use --no-playback instead.");
// fall through
case 'N':
opts->video_playback = false;
opts->audio_playback = false;
@@ -2558,9 +2473,32 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->key_inject_mode = SC_KEY_INJECT_MODE_RAW;
break;
case OPT_ROTATION:
LOGE("--rotation has been removed, use --orientation or "
"--capture-orientation instead.");
return false;
LOGW("--rotation is deprecated, use --display-orientation "
"instead.");
uint8_t rotation;
if (!parse_rotation(optarg, &rotation)) {
return false;
}
assert(rotation <= 3);
switch (rotation) {
case 0:
opts->display_orientation = SC_ORIENTATION_0;
break;
case 1:
// rotation 1 was 90° counterclockwise, but orientation
// is expressed clockwise
opts->display_orientation = SC_ORIENTATION_270;
break;
case 2:
opts->display_orientation = SC_ORIENTATION_180;
break;
case 3:
// rotation 3 was 270° counterclockwise, but orientation
// is expressed clockwise
opts->display_orientation = SC_ORIENTATION_90;
break;
}
break;
case OPT_DISPLAY_ORIENTATION:
if (!parse_orientation(optarg, &opts->display_orientation)) {
return false;
@@ -2621,9 +2559,23 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
}
break;
case OPT_FORWARD_ALL_CLICKS:
LOGE("--forward-all-clicks has been removed, "
LOGW("--forward-all-clicks is deprecated, "
"use --mouse-bind=++++ instead.");
return false;
opts->mouse_bindings = (struct sc_mouse_bindings) {
.pri = {
.right_click = SC_MOUSE_BINDING_CLICK,
.middle_click = SC_MOUSE_BINDING_CLICK,
.click4 = SC_MOUSE_BINDING_CLICK,
.click5 = SC_MOUSE_BINDING_CLICK,
},
.sec = {
.right_click = SC_MOUSE_BINDING_CLICK,
.middle_click = SC_MOUSE_BINDING_CLICK,
.click4 = SC_MOUSE_BINDING_CLICK,
.click5 = SC_MOUSE_BINDING_CLICK,
},
};
break;
case OPT_LEGACY_PASTE:
opts->legacy_paste = true;
break;
@@ -2631,9 +2583,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->power_off_on_close = true;
break;
case OPT_DISPLAY_BUFFER:
LOGE("--display-buffer has been removed, use --video-buffer "
LOGW("--display-buffer is deprecated, use --video-buffer "
"instead.");
return false;
// fall through
case OPT_VIDEO_BUFFER:
if (!parse_buffering_time(optarg, &opts->video_buffer)) {
return false;
@@ -2806,21 +2758,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false;
}
break;
case OPT_ANGLE:
opts->angle = optarg;
break;
case OPT_NO_VD_DESTROY_CONTENT:
opts->vd_destroy_content = false;
break;
case OPT_NO_VD_SYSTEM_DECORATIONS:
opts->vd_system_decorations = false;
break;
case OPT_DISPLAY_IME_POLICY:
if (!parse_display_ime_policy(optarg,
&opts->display_ime_policy)) {
return false;
}
break;
default:
// getopt prints the error message on stderr
return false;
@@ -2859,10 +2796,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
#endif
if (!opts->window) {
// Without window, there cannot be any video playback
// Without window, there cannot be any video playback or control
opts->video_playback = false;
// Controls are still possible, allowing for options like
// --turn-screen-off
opts->control = false;
}
if (!opts->video) {
@@ -2916,6 +2852,14 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false;
}
if (opts->lock_video_orientation ==
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_AUTO;
}
// V4L2 could not handle size change.
// Do not log because downsizing on error is the default behavior,
// not an explicit request from the user.
@@ -3005,6 +2949,13 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
LOGE("--new-display is incompatible with --no-video");
return false;
}
if (opts->max_size && opts->new_display[0] != '\0'
&& opts->new_display[0] != '/') {
// An explicit size is defined (not "" nor "/<dpi>")
LOGE("Cannot specify both --new-display size and -m/--max-size");
return false;
}
}
if (otg) {
@@ -3077,12 +3028,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false;
}
if (opts->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED) {
LOGE("--display-ime-policy is only available with "
"--video-source=display");
return false;
}
if (opts->camera_id && opts->camera_facing != SC_CAMERA_FACING_ANY) {
LOGE("Cannot specify both --camera-id and --camera-facing");
return false;
@@ -3124,12 +3069,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
return false;
}
if (opts->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED
&& opts->display_id == 0 && !opts->new_display) {
LOGE("--display-ime-policy is only supported on a secondary display");
return false;
}
if (opts->audio && opts->audio_source == SC_AUDIO_SOURCE_AUTO) {
// Select the audio source according to the video source
if (opts->video_source == SC_VIDEO_SOURCE_DISPLAY) {

View File

@@ -75,14 +75,6 @@
# define SCRCPY_SDL_HAS_THREAD_PRIORITY_TIME_CRITICAL
#endif
#if SDL_VERSION_ATLEAST(2, 0, 18)
# define SCRCPY_SDL_HAS_HINT_APP_NAME
#endif
#if SDL_VERSION_ATLEAST(2, 0, 14)
# define SCRCPY_SDL_HAS_HINT_AUDIO_DEVICE_APP_NAME
#endif
#ifndef HAVE_STRDUP
char *strdup(const char *s);
#endif

View File

@@ -127,14 +127,10 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) {
return 32;
case SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
write_position(&buf[1], &msg->inject_scroll_event.position);
// Accept values in the range [-16, 16].
// Normalize to [-1, 1] in order to use sc_float_to_i16fp().
float hscroll_norm = msg->inject_scroll_event.hscroll / 16;
hscroll_norm = CLAMP(hscroll_norm, -1, 1);
float vscroll_norm = msg->inject_scroll_event.vscroll / 16;
vscroll_norm = CLAMP(vscroll_norm, -1, 1);
int16_t hscroll = sc_float_to_i16fp(hscroll_norm);
int16_t vscroll = sc_float_to_i16fp(vscroll_norm);
int16_t hscroll =
sc_float_to_i16fp(msg->inject_scroll_event.hscroll);
int16_t vscroll =
sc_float_to_i16fp(msg->inject_scroll_event.vscroll);
sc_write16be(&buf[13], (uint16_t) hscroll);
sc_write16be(&buf[15], (uint16_t) vscroll);
sc_write32be(&buf[17], msg->inject_scroll_event.buttons);
@@ -156,10 +152,8 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) {
return 2;
case SC_CONTROL_MSG_TYPE_UHID_CREATE:
sc_write16be(&buf[1], msg->uhid_create.id);
sc_write16be(&buf[3], msg->uhid_create.vendor_id);
sc_write16be(&buf[5], msg->uhid_create.product_id);
size_t index = 7;
size_t index = 3;
index += write_string_tiny(&buf[index], msg->uhid_create.name, 127);
sc_write16be(&buf[index], msg->uhid_create.report_desc_size);
@@ -284,13 +278,9 @@ sc_control_msg_log(const struct sc_control_msg *msg) {
// Quote only if name is not null
const char *name = msg->uhid_create.name;
const char *quote = name ? "\"" : "";
LOG_CMSG("UHID create [%" PRIu16 "] %04" PRIx16 ":%04" PRIx16
" name=%s%s%s report_desc_size=%" PRIu16,
msg->uhid_create.id,
msg->uhid_create.vendor_id,
msg->uhid_create.product_id,
quote, name, quote,
msg->uhid_create.report_desc_size);
LOG_CMSG("UHID create [%" PRIu16 "] name=%s%s%s "
"report_desc_size=%" PRIu16, msg->uhid_create.id,
quote, name, quote, msg->uhid_create.report_desc_size);
break;
}
case SC_CONTROL_MSG_TYPE_UHID_INPUT: {

View File

@@ -94,8 +94,6 @@ struct sc_control_msg {
} set_display_power;
struct {
uint16_t id;
uint16_t vendor_id;
uint16_t product_id;
const char *name; // pointer to static data
uint16_t report_desc_size;
const uint8_t *report_desc; // pointer to static data

View File

@@ -1,9 +1,11 @@
#include "decoder.h"
#include <errno.h>
#include <libavcodec/packet.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/channel_layout.h>
#include "events.h"
#include "trait/frame_sink.h"
#include "util/log.h"
/** Downcast packet_sink to decoder */

View File

@@ -3,11 +3,13 @@
#include "common.h"
#include <libavcodec/avcodec.h>
#include "trait/frame_source.h"
#include "trait/packet_sink.h"
#include <stdbool.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
struct sc_decoder {
struct sc_packet_sink packet_sink; // packet sink trait
struct sc_frame_source frame_source; // frame source trait

View File

@@ -2,7 +2,9 @@
#include <assert.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include "util/log.h"

View File

@@ -4,7 +4,6 @@
#include "common.h"
#include <stdbool.h>
#include <libavutil/frame.h>
#include "clock.h"
#include "trait/frame_source.h"

View File

@@ -1,11 +1,14 @@
#include "demuxer.h"
#include <assert.h>
#include <inttypes.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/time.h>
#include <unistd.h>
#include "decoder.h"
#include "events.h"
#include "packet_merger.h"
#include "recorder.h"
#include "util/binary.h"
#include "util/log.h"

View File

@@ -4,8 +4,12 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include "trait/packet_source.h"
#include "trait/packet_sink.h"
#include "util/net.h"
#include "util/thread.h"

View File

@@ -53,7 +53,7 @@ sc_device_msg_deserialize(const uint8_t *buf, size_t len,
}
uint16_t id = sc_read16be(&buf[1]);
size_t size = sc_read16be(&buf[3]);
if (size > len - 5) {
if (size < len - 5) {
return 0; // not available
}
uint8_t *data = malloc(size);

View File

@@ -3,9 +3,9 @@
#include "common.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#define DEVICE_MSG_MAX_SIZE (1 << 18) // 256k
// type: 1 byte; length: 4 bytes

View File

@@ -1,8 +1,6 @@
#include "display.h"
#include <assert.h>
#include <inttypes.h>
#include <string.h>
#include <libavutil/pixfmt.h>
#include "util/log.h"
@@ -170,7 +168,6 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
}
}
av_frame_unref(display->pending.frame);
int r = av_frame_ref(display->pending.frame, frame);
if (r) {
LOGE("Could not ref frame: %d", r);
@@ -182,11 +179,6 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
return true;
}
// Forward declaration
static bool
sc_display_update_texture_internal(struct sc_display *display,
const AVFrame *frame);
static bool
sc_display_apply_pending(struct sc_display *display) {
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
@@ -202,8 +194,7 @@ sc_display_apply_pending(struct sc_display *display) {
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
assert(display->pending.frame);
bool ok = sc_display_update_texture_internal(display,
display->pending.frame);
bool ok = sc_display_update_texture(display, display->pending.frame);
if (!ok) {
return false;
}

View File

@@ -4,8 +4,7 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <libavutil/frame.h>
#include <libavformat/avformat.h>
#include <SDL2/SDL.h>
#include "coords.h"
@@ -22,7 +21,7 @@ struct sc_display {
struct sc_opengl gl;
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
SDL_GLContext gl_context;
SDL_GLContext *gl_context;
#endif
bool mipmaps;

View File

@@ -1,7 +1,5 @@
#include "events.h"
#include <assert.h>
#include "util/log.h"
#include "util/thread.h"

View File

@@ -1,11 +1,11 @@
#include "file_pusher.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "adb/adb.h"
#include "util/log.h"
#include "util/process_intr.h"
#define DEFAULT_PUSH_TARGET "/sdcard/Download/"

View File

@@ -1,7 +1,6 @@
#include "fps_counter.h"
#include <assert.h>
#include <stdint.h>
#include "util/log.h"

View File

@@ -5,9 +5,9 @@
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include "util/thread.h"
#include "util/tick.h"
struct sc_fps_counter {
sc_thread thread;

View File

@@ -1,6 +1,8 @@
#include "frame_buffer.h"
#include <assert.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include "util/log.h"

View File

@@ -4,7 +4,6 @@
#include "common.h"
#include <stdbool.h>
#include <libavutil/frame.h>
#include "util/thread.h"

View File

@@ -3,7 +3,6 @@
#include "common.h"
#include <stddef.h>
#include <stdint.h>
#define SC_HID_MAX_SIZE 15
@@ -16,6 +15,7 @@ struct sc_hid_input {
struct sc_hid_open {
uint16_t hid_id;
const char *name; // pointer to static memory
const uint8_t *report_desc; // pointer to static memory
size_t report_desc_size;
};

View File

@@ -2,8 +2,6 @@
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <sys/types.h>
#include "util/binary.h"
#include "util/log.h"
@@ -54,10 +52,10 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x09, 0x30,
// Usage (Y) Left stick y
0x09, 0x31,
// Usage (Rx) Right stick x
0x09, 0x33,
// Usage (Ry) Right stick y
0x09, 0x34,
// Usage (Z) Right stick x
0x09, 0x32,
// Usage (Rz) Right stick y
0x09, 0x35,
// Logical Minimum (0)
0x15, 0x00,
// Logical Maximum (65535)
@@ -67,15 +65,15 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x75, 0x10,
// Report Count (4)
0x95, 0x04,
// Input (Data, Variable, Absolute): 4x2 bytes (X, Y, Z, Rz)
// Input (Data, Variable, Absolute): 4 bytes (X, Y, Z, Rz)
0x81, 0x02,
// Usage Page (Generic Desktop)
0x05, 0x01,
// Usage (Z)
0x09, 0x32,
// Usage (Rz)
0x09, 0x35,
// Usage Page (Simulation Controls)
0x05, 0x02,
// Usage (Brake)
0x09, 0xC5,
// Usage (Accelerator)
0x09, 0xC4,
// Logical Minimum (0)
0x15, 0x00,
// Logical Maximum (32767)
@@ -84,7 +82,7 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x75, 0x10,
// Report Count (2)
0x95, 0x02,
// Input (Data, Variable, Absolute): 2x2 bytes (L2, R2)
// Input (Data, Variable, Absolute): 2 bytes (L2, R2)
0x81, 0x02,
// Usage Page (Buttons)
@@ -184,7 +182,7 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
* `------------- SC_GAMEPAD_BUTTON_RIGHT_STICK
*
* +---------------+
* byte 14: |0 0 0 0 . . . .| hat switch (dpad) position (0-8)
* byte 14: |0 0 0 . . . . .| hat switch (dpad) position (0-8)
* +---------------+
* 9 possible positions and their values:
* 8 1 2
@@ -193,19 +191,16 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
* (8 is top-left, 1 is top, 2 is top-right, etc.)
*/
// [-32768 to 32767] -> [0 to 65535]
#define AXIS_RESCALE(V) (uint16_t) (((int32_t) V) + 0x8000)
static void
sc_hid_gamepad_slot_init(struct sc_hid_gamepad_slot *slot,
uint32_t gamepad_id) {
assert(gamepad_id != SC_GAMEPAD_ID_INVALID);
slot->gamepad_id = gamepad_id;
slot->buttons = 0;
slot->axis_left_x = AXIS_RESCALE(0);
slot->axis_left_y = AXIS_RESCALE(0);
slot->axis_right_x = AXIS_RESCALE(0);
slot->axis_right_y = AXIS_RESCALE(0);
slot->axis_left_x = 0;
slot->axis_left_y = 0;
slot->axis_right_x = 0;
slot->axis_right_y = 0;
slot->axis_left_trigger = 0;
slot->axis_right_trigger = 0;
}
@@ -248,8 +243,14 @@ sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
sc_hid_gamepad_slot_init(&hid->slots[slot_idx], gamepad_id);
SDL_GameController* game_controller =
SDL_GameControllerFromInstanceID(gamepad_id);
assert(game_controller);
const char *name = SDL_GameControllerName(game_controller);
uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx);
hid_open->hid_id = hid_id;
hid_open->name = name;
hid_open->report_desc = SC_HID_GAMEPAD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_GAMEPAD_REPORT_DESC);
@@ -422,6 +423,8 @@ sc_hid_gamepad_generate_input_from_axis(struct sc_hid_gamepad *hid,
struct sc_hid_gamepad_slot *slot = &hid->slots[slot_idx];
// [-32768 to 32767] -> [0 to 65535]
#define AXIS_RESCALE(V) (uint16_t) (((int32_t) V) + 0x8000)
switch (event->axis) {
case SC_GAMEPAD_AXIS_LEFTX:
slot->axis_left_x = AXIS_RESCALE(event->value);

View File

@@ -4,7 +4,6 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include "hid/hid_event.h"
#include "input_events.h"

View File

@@ -1,6 +1,5 @@
#include "hid_keyboard.h"
#include <assert.h>
#include <string.h>
#include "util/log.h"
@@ -336,6 +335,7 @@ sc_hid_keyboard_generate_input_from_mods(struct sc_hid_input *hid_input,
void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_KEYBOARD;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_KEYBOARD_REPORT_DESC);
}

View File

@@ -4,7 +4,6 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include "hid/hid_event.h"
#include "input_events.h"

View File

@@ -1,10 +1,8 @@
#include "hid_mouse.h"
#include <stdint.h>
// 1 byte for buttons + padding, 1 byte for X position, 1 byte for Y position,
// 1 byte for wheel motion, 1 byte for hozizontal scrolling
#define SC_HID_MOUSE_INPUT_SIZE 5
// 1 byte for wheel motion
#define SC_HID_MOUSE_INPUT_SIZE 4
/**
* Mouse descriptor from the specification:
@@ -75,21 +73,6 @@ static const uint8_t SC_HID_MOUSE_REPORT_DESC[] = {
// Input (Data, Variable, Relative): 3 position bytes (X, Y, Wheel)
0x81, 0x06,
// Usage Page (Consumer Page)
0x05, 0x0C,
// Usage(AC Pan)
0x0A, 0x38, 0x02,
// Logical Minimum (-127)
0x15, 0x81,
// Logical Maximum (127)
0x25, 0x7F,
// Report Size (8)
0x75, 0x08,
// Report Count (1)
0x95, 0x01,
// Input (Data, Variable, Relative): 1 byte (AC Pan)
0x81, 0x06,
// End Collection
0xC0,
@@ -175,8 +158,7 @@ sc_hid_mouse_generate_input_from_motion(struct sc_hid_input *hid_input,
data[0] = sc_hid_buttons_from_buttons_state(event->buttons_state);
data[1] = CLAMP(event->xrel, -127, 127);
data[2] = CLAMP(event->yrel, -127, 127);
data[3] = 0; // no vertical scrolling
data[4] = 0; // no horizontal scrolling
data[3] = 0; // wheel coordinates only used for scrolling
}
void
@@ -188,31 +170,27 @@ sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input,
data[0] = sc_hid_buttons_from_buttons_state(event->buttons_state);
data[1] = 0; // no x motion
data[2] = 0; // no y motion
data[3] = 0; // no vertical scrolling
data[4] = 0; // no horizontal scrolling
data[3] = 0; // wheel coordinates only used for scrolling
}
bool
void
sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input,
const struct sc_mouse_scroll_event *event) {
if (!event->vscroll_int && !event->hscroll_int) {
// Need a full integral value for HID
return false;
}
sc_hid_mouse_input_init(hid_input);
uint8_t *data = hid_input->data;
data[0] = 0; // buttons state irrelevant (and unknown)
data[1] = 0; // no x motion
data[2] = 0; // no y motion
data[3] = CLAMP(event->vscroll_int, -127, 127);
data[4] = CLAMP(event->hscroll_int, -127, 127);
return true;
// In practice, vscroll is always -1, 0 or 1, but in theory other values
// are possible
data[3] = CLAMP(event->vscroll, -127, 127);
// Horizontal scrolling ignored
}
void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_MOUSE;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_MOUSE_REPORT_DESC);
}

View File

@@ -3,6 +3,8 @@
#include "common.h"
#include <stdbool.h>
#include "hid/hid_event.h"
#include "input_events.h"
@@ -22,7 +24,7 @@ void
sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input,
const struct sc_mouse_click_event *event);
bool
void
sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input,
const struct sc_mouse_scroll_event *event);

View File

@@ -2,22 +2,16 @@
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/pixdesc.h>
#include <libavutil/pixfmt.h>
#include <SDL2/SDL.h>
#include "config.h"
#include "util/env.h"
#ifdef PORTABLE
# include "util/file.h"
#endif
#include "compat.h"
#include "util/file.h"
#include "util/log.h"
#include "util/str.h"
#define SCRCPY_PORTABLE_ICON_FILENAME "icon.png"
#define SCRCPY_DEFAULT_ICON_PATH \
@@ -25,22 +19,35 @@
static char *
get_icon_path(void) {
char *icon_path = sc_get_env("SCRCPY_ICON_PATH");
if (icon_path) {
#ifdef __WINDOWS__
const wchar_t *icon_path_env = _wgetenv(L"SCRCPY_ICON_PATH");
#else
const char *icon_path_env = getenv("SCRCPY_ICON_PATH");
#endif
if (icon_path_env) {
// if the envvar is set, use it
#ifdef __WINDOWS__
char *icon_path = sc_str_from_wchars(icon_path_env);
#else
char *icon_path = strdup(icon_path_env);
#endif
if (!icon_path) {
LOG_OOM();
return NULL;
}
LOGD("Using SCRCPY_ICON_PATH: %s", icon_path);
return icon_path;
}
#ifndef PORTABLE
LOGD("Using icon: " SCRCPY_DEFAULT_ICON_PATH);
icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
char *icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
if (!icon_path) {
LOG_OOM();
return NULL;
}
#else
icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
char *icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
if (!icon_path) {
LOGE("Could not get icon path");
return NULL;

View File

@@ -3,7 +3,9 @@
#include "common.h"
#include <SDL2/SDL_surface.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <libavformat/avformat.h>
SDL_Surface *
scrcpy_icon_load(void);

View File

@@ -9,6 +9,7 @@
#include <SDL2/SDL_events.h>
#include "coords.h"
#include "options.h"
/* The representation of input events in scrcpy is very close to the SDL API,
* for simplicity.
@@ -393,8 +394,6 @@ struct sc_mouse_scroll_event {
struct sc_position position;
float hscroll;
float vscroll;
int32_t hscroll_int;
int32_t vscroll_int;
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
};
@@ -413,12 +412,18 @@ struct sc_touch_event {
float pressure;
};
enum sc_gamepad_device_event_type {
SC_GAMEPAD_DEVICE_ADDED,
SC_GAMEPAD_DEVICE_REMOVED,
};
// As documented in <https://wiki.libsdl.org/SDL2/SDL_JoystickID>:
// The ID value starts at 0 and increments from there. The value -1 is an
// invalid ID.
#define SC_GAMEPAD_ID_INVALID UINT32_C(-1)
struct sc_gamepad_device_event {
enum sc_gamepad_device_event_type type;
uint32_t gamepad_id;
};
@@ -498,6 +503,16 @@ sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) {
return buttons_state;
}
static inline enum sc_gamepad_device_event_type
sc_gamepad_device_event_type_from_sdl_type(uint32_t type) {
assert(type == SDL_CONTROLLERDEVICEADDED
|| type == SDL_CONTROLLERDEVICEREMOVED);
if (type == SDL_CONTROLLERDEVICEADDED) {
return SC_GAMEPAD_DEVICE_ADDED;
}
return SC_GAMEPAD_DEVICE_REMOVED;
}
static inline enum sc_gamepad_axis
sc_gamepad_axis_from_sdl(uint8_t axis) {
if (axis <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {

View File

@@ -1,12 +1,8 @@
#include "input_manager.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_keycode.h>
#include "android/input.h"
#include "android/keycodes.h"
#include "input_events.h"
#include "screen.h"
#include "shortcut_mod.h"
@@ -897,14 +893,12 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
struct sc_mouse_scroll_event evt = {
.position = sc_input_manager_get_position(im, mouse_x, mouse_y),
#if SDL_VERSION_ATLEAST(2, 0, 18)
.hscroll = event->preciseX,
.vscroll = event->preciseY,
.hscroll = CLAMP(event->preciseX, -1.0f, 1.0f),
.vscroll = CLAMP(event->preciseY, -1.0f, 1.0f),
#else
.hscroll = event->x,
.vscroll = event->y,
.hscroll = CLAMP(event->x, -1, 1),
.vscroll = CLAMP(event->y, -1, 1),
#endif
.hscroll_int = event->x,
.vscroll_int = event->y,
.buttons_state = im->mouse_buttons_state,
};
@@ -914,6 +908,7 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
static void
sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
const SDL_ControllerDeviceEvent *event) {
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) {
@@ -928,12 +923,9 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
return;
}
struct sc_gamepad_device_event evt = {
.gamepad_id = SDL_JoystickInstanceID(joystick),
};
im->gp->ops->process_gamepad_added(im->gp, &evt);
id = SDL_JoystickInstanceID(joystick);
} else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
SDL_JoystickID id = event->which;
id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) {
@@ -941,15 +933,16 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
} else {
LOGW("Unknown gamepad device removed");
}
struct sc_gamepad_device_event evt = {
.gamepad_id = id,
};
im->gp->ops->process_gamepad_removed(im->gp, &evt);
} else {
// Nothing to do
return;
}
struct sc_gamepad_device_event evt = {
.type = sc_gamepad_device_event_type_from_sdl_type(event->type),
.gamepad_id = id,
};
im->gp->ops->process_gamepad_device(im->gp, &evt);
}
static void

View File

@@ -4,12 +4,12 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL.h>
#include "controller.h"
#include "file_pusher.h"
#include "fps_counter.h"
#include "options.h"
#include "trait/gamepad_processor.h"
#include "trait/key_processor.h"

View File

@@ -1,13 +1,8 @@
#include "keyboard_sdk.h"
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "android/input.h"
#include "android/keycodes.h"
#include "control_msg.h"
#include "controller.h"
#include "input_events.h"

View File

@@ -1,7 +1,9 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <libavformat/avformat.h>
#ifdef HAVE_V4L2
# include <libavdevice/avdevice.h>
#endif

View File

@@ -1,12 +1,12 @@
#include "mouse_sdk.h"
#include <assert.h>
#include <stdint.h>
#include "android/input.h"
#include "control_msg.h"
#include "controller.h"
#include "input_events.h"
#include "util/intmap.h"
#include "util/log.h"
/** Downcast mouse processor to sc_mouse_sdk */

View File

@@ -6,6 +6,7 @@
#include <stdbool.h>
#include "controller.h"
#include "screen.h"
#include "trait/mouse_processor.h"
struct sc_mouse_sdk {

View File

@@ -2,8 +2,7 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <SDL2/SDL.h>
#include "SDL2/SDL.h"
void
sc_opengl_init(struct sc_opengl *gl) {

View File

@@ -1,7 +1,5 @@
#include "options.h"
#include <stddef.h>
const struct scrcpy_options scrcpy_options_default = {
.serial = NULL,
.crop = NULL,
@@ -52,11 +50,9 @@ const struct scrcpy_options scrcpy_options_default = {
.video_bit_rate = 0,
.audio_bit_rate = 0,
.max_fps = NULL,
.capture_orientation = SC_ORIENTATION_0,
.capture_orientation_lock = SC_ORIENTATION_UNLOCKED,
.lock_video_orientation = SC_LOCK_VIDEO_ORIENTATION_UNLOCKED,
.display_orientation = SC_ORIENTATION_0,
.record_orientation = SC_ORIENTATION_0,
.display_ime_policy = SC_DISPLAY_IME_POLICY_UNDEFINED,
.window_x = SC_WINDOW_POSITION_UNDEFINED,
.window_y = SC_WINDOW_POSITION_UNDEFINED,
.window_width = 0,
@@ -110,9 +106,6 @@ const struct scrcpy_options scrcpy_options_default = {
.audio_dup = false,
.new_display = NULL,
.start_app = NULL,
.angle = NULL,
.vd_destroy_content = true,
.vd_system_decorations = true,
};
enum sc_orientation

View File

@@ -5,6 +5,7 @@
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "util/tick.h"
@@ -59,14 +60,6 @@ enum sc_audio_source {
SC_AUDIO_SOURCE_OUTPUT,
SC_AUDIO_SOURCE_MIC,
SC_AUDIO_SOURCE_PLAYBACK,
SC_AUDIO_SOURCE_MIC_UNPROCESSED,
SC_AUDIO_SOURCE_MIC_CAMCORDER,
SC_AUDIO_SOURCE_MIC_VOICE_RECOGNITION,
SC_AUDIO_SOURCE_MIC_VOICE_COMMUNICATION,
SC_AUDIO_SOURCE_VOICE_CALL,
SC_AUDIO_SOURCE_VOICE_CALL_UPLINK,
SC_AUDIO_SOURCE_VOICE_CALL_DOWNLINK,
SC_AUDIO_SOURCE_VOICE_PERFORMANCE,
};
enum sc_camera_facing {
@@ -91,19 +84,6 @@ enum sc_orientation { // v v v
SC_ORIENTATION_FLIP_270, // 1 1 1
};
enum sc_orientation_lock {
SC_ORIENTATION_UNLOCKED,
SC_ORIENTATION_LOCKED_VALUE, // lock to specified orientation
SC_ORIENTATION_LOCKED_INITIAL, // lock to initial device orientation
};
enum sc_display_ime_policy {
SC_DISPLAY_IME_POLICY_UNDEFINED,
SC_DISPLAY_IME_POLICY_LOCAL,
SC_DISPLAY_IME_POLICY_FALLBACK,
SC_DISPLAY_IME_POLICY_HIDE,
};
static inline bool
sc_orientation_is_mirror(enum sc_orientation orientation) {
assert(!(orientation & ~7));
@@ -150,6 +130,18 @@ sc_orientation_get_name(enum sc_orientation orientation) {
}
}
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,
SC_LOCK_VIDEO_ORIENTATION_270 = 1,
};
enum sc_keyboard_input_mode {
SC_KEYBOARD_INPUT_MODE_AUTO,
SC_KEYBOARD_INPUT_MODE_UHID_OR_AOA, // normal vs otg mode
@@ -261,12 +253,9 @@ struct scrcpy_options {
uint32_t video_bit_rate;
uint32_t audio_bit_rate;
const char *max_fps; // float to be parsed by the server
const char *angle; // float to be parsed by the server
enum sc_orientation capture_orientation;
enum sc_orientation_lock capture_orientation_lock;
enum sc_lock_video_orientation lock_video_orientation;
enum sc_orientation display_orientation;
enum sc_orientation record_orientation;
enum sc_display_ime_policy display_ime_policy;
int16_t window_x; // SC_WINDOW_POSITION_UNDEFINED for "auto"
int16_t window_y; // SC_WINDOW_POSITION_UNDEFINED for "auto"
uint16_t window_width;
@@ -325,8 +314,6 @@ struct scrcpy_options {
bool audio_dup;
const char *new_display; // [<width>x<height>][/<dpi>] parsed by the server
const char *start_app;
bool vd_destroy_content;
bool vd_system_decorations;
};
extern const struct scrcpy_options scrcpy_options_default;

View File

@@ -1,9 +1,5 @@
#include "packet_merger.h"
#include <stdlib.h>
#include <string.h>
#include <libavutil/avutil.h>
#include "util/log.h"
void

View File

@@ -5,7 +5,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <libavcodec/packet.h>
#include <libavcodec/avcodec.h>
/**
* Config packets (containing the SPS/PPS) are sent in-band. A new config

View File

@@ -2,6 +2,7 @@
#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <SDL2/SDL_clipboard.h>
#include "device_msg.h"

View File

@@ -1,9 +1,6 @@
#include "recorder.h"
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/time.h>
@@ -146,14 +143,8 @@ sc_recorder_open_output_file(struct sc_recorder *recorder) {
return false;
}
char *file_url = sc_str_concat("file:", recorder->filename);
if (!file_url) {
avformat_free_context(recorder->ctx);
return false;
}
int ret = avio_open(&recorder->ctx->pb, file_url, AVIO_FLAG_WRITE);
free(file_url);
int ret = avio_open(&recorder->ctx->pb, recorder->filename,
AVIO_FLAG_WRITE);
if (ret < 0) {
LOGE("Failed to open output file: %s", recorder->filename);
avformat_free_context(recorder->ctx);

View File

@@ -4,10 +4,9 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <libavcodec/packet.h>
#include <libavformat/avformat.h>
#include "coords.h"
#include "options.h"
#include "trait/packet_sink.h"
#include "util/thread.h"

View File

@@ -1,11 +1,10 @@
#include "scrcpy.h"
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libavformat/avformat.h>
#include <sys/time.h>
#include <SDL2/SDL.h>
#ifdef _WIN32
@@ -38,9 +37,9 @@
#endif
#include "util/acksync.h"
#include "util/log.h"
#include "util/net.h"
#include "util/rand.h"
#include "util/timeout.h"
#include "util/tick.h"
#ifdef HAVE_V4L2
# include "v4l2_sink.h"
#endif
@@ -93,7 +92,7 @@ struct scrcpy {
#ifdef _WIN32
static BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
if (ctrl_type == CTRL_C_EVENT || ctrl_type == CTRL_BREAK_EVENT) {
if (ctrl_type == CTRL_C_EVENT) {
sc_push_event(SDL_QUIT);
return TRUE;
}
@@ -107,17 +106,6 @@ sdl_set_hints(const char *render_driver) {
LOGW("Could not set render driver");
}
// App name used in various contexts (such as PulseAudio)
#if defined(SCRCPY_SDL_HAS_HINT_APP_NAME)
if (!SDL_SetHint(SDL_HINT_APP_NAME, "scrcpy")) {
LOGW("Could not set app name");
}
#elif defined(SCRCPY_SDL_HAS_HINT_AUDIO_DEVICE_APP_NAME)
if (!SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "scrcpy")) {
LOGW("Could not set audio device app name");
}
#endif
// Linear filtering
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
LOGW("Could not enable linear filtering");
@@ -176,7 +164,7 @@ sdl_configure(bool video_playback, bool disable_screensaver) {
}
static enum scrcpy_exit_code
event_loop(struct scrcpy *s, bool has_screen) {
event_loop(struct scrcpy *s) {
SDL_Event event;
while (SDL_WaitEvent(&event)) {
switch (event.type) {
@@ -208,7 +196,7 @@ event_loop(struct scrcpy *s, bool has_screen) {
break;
}
default:
if (has_screen && !sc_screen_handle_event(&s->screen, &event)) {
if (!sc_screen_handle_event(&s->screen, &event)) {
return SCRCPY_EXIT_FAILURE;
}
break;
@@ -440,14 +428,11 @@ scrcpy(struct scrcpy_options *options) {
.video_bit_rate = options->video_bit_rate,
.audio_bit_rate = options->audio_bit_rate,
.max_fps = options->max_fps,
.angle = options->angle,
.screen_off_timeout = options->screen_off_timeout,
.capture_orientation = options->capture_orientation,
.capture_orientation_lock = options->capture_orientation_lock,
.lock_video_orientation = options->lock_video_orientation,
.control = options->control,
.display_id = options->display_id,
.new_display = options->new_display,
.display_ime_policy = options->display_ime_policy,
.video = options->video,
.audio = options->audio,
.audio_dup = options->audio_dup,
@@ -471,8 +456,6 @@ scrcpy(struct scrcpy_options *options) {
.power_on = options->power_on,
.kill_adb_on_close = options->kill_adb_on_close,
.camera_high_speed = options->camera_high_speed,
.vd_destroy_content = options->vd_destroy_content,
.vd_system_decorations = options->vd_system_decorations,
.list = options->list,
};
@@ -944,7 +927,7 @@ aoa_complete:
}
}
ret = event_loop(s, options->window);
ret = event_loop(s);
terminate_event_loop();
LOGD("quit...");

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include <stdbool.h>
#include "options.h"
enum scrcpy_exit_code {

View File

@@ -225,7 +225,7 @@ sc_screen_render_novideo(struct sc_screen *screen) {
(void) res; // any error already logged
}
#if defined(__APPLE__) || defined(_WIN32)
#if defined(__APPLE__) || defined(__WINDOWS__)
# define CONTINUOUS_RESIZING_WORKAROUND
#endif
@@ -409,7 +409,7 @@ sc_screen_init(struct sc_screen *screen,
} else {
// without video, the icon is used as window content, it must be present
LOGE("Could not load icon");
goto error_destroy_window;
goto error_destroy_fps_counter;
}
SDL_Surface *icon_novideo = params->video ? NULL : icon;

View File

@@ -1,14 +1,11 @@
#ifndef SC_SCREEN_H
#define SC_SCREEN_H
#ifndef SCREEN_H
#define SCREEN_H
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <SDL2/SDL.h>
#include <libavcodec/avcodec.h>
#include <libavutil/frame.h>
#include <libavutil/pixfmt.h>
#include <libavformat/avformat.h>
#include "controller.h"
#include "coords.h"
@@ -17,6 +14,7 @@
#include "frame_buffer.h"
#include "input_manager.h"
#include "mouse_capture.h"
#include "opengl.h"
#include "options.h"
#include "trait/key_processor.h"
#include "trait/frame_sink.h"

View File

@@ -1,18 +1,18 @@
#include "server.h"
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_platform.h>
#include "adb/adb.h"
#include "util/env.h"
#include "util/binary.h"
#include "util/file.h"
#include "util/log.h"
#include "util/net_intr.h"
#include "util/process.h"
#include "util/process_intr.h"
#include "util/str.h"
#define SC_SERVER_FILENAME "scrcpy-server"
@@ -25,22 +25,35 @@
static char *
get_server_path(void) {
char *server_path = sc_get_env("SCRCPY_SERVER_PATH");
if (server_path) {
#ifdef __WINDOWS__
const wchar_t *server_path_env = _wgetenv(L"SCRCPY_SERVER_PATH");
#else
const char *server_path_env = getenv("SCRCPY_SERVER_PATH");
#endif
if (server_path_env) {
// if the envvar is set, use it
#ifdef __WINDOWS__
char *server_path = sc_str_from_wchars(server_path_env);
#else
char *server_path = strdup(server_path_env);
#endif
if (!server_path) {
LOG_OOM();
return NULL;
}
LOGD("Using SCRCPY_SERVER_PATH: %s", server_path);
return server_path;
}
#ifndef PORTABLE
LOGD("Using server: " SC_SERVER_PATH_DEFAULT);
server_path = strdup(SC_SERVER_PATH_DEFAULT);
char *server_path = strdup(SC_SERVER_PATH_DEFAULT);
if (!server_path) {
LOG_OOM();
return NULL;
}
#else
server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
char *server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
if (!server_path) {
LOGE("Could not get local file path, "
"using " SC_SERVER_FILENAME " from current directory");
@@ -149,43 +162,12 @@ sc_server_get_audio_source_name(enum sc_audio_source audio_source) {
return "mic";
case SC_AUDIO_SOURCE_PLAYBACK:
return "playback";
case SC_AUDIO_SOURCE_MIC_UNPROCESSED:
return "mic-unprocessed";
case SC_AUDIO_SOURCE_MIC_CAMCORDER:
return "mic-camcorder";
case SC_AUDIO_SOURCE_MIC_VOICE_RECOGNITION:
return "mic-voice-recognition";
case SC_AUDIO_SOURCE_MIC_VOICE_COMMUNICATION:
return "mic-voice-communication";
case SC_AUDIO_SOURCE_VOICE_CALL:
return "voice-call";
case SC_AUDIO_SOURCE_VOICE_CALL_UPLINK:
return "voice-call-uplink";
case SC_AUDIO_SOURCE_VOICE_CALL_DOWNLINK:
return "voice-call-downlink";
case SC_AUDIO_SOURCE_VOICE_PERFORMANCE:
return "voice-performance";
default:
assert(!"unexpected audio source");
return NULL;
}
}
static const char *
sc_server_get_display_ime_policy_name(enum sc_display_ime_policy policy) {
switch (policy) {
case SC_DISPLAY_IME_POLICY_LOCAL:
return "local";
case SC_DISPLAY_IME_POLICY_FALLBACK:
return "fallback";
case SC_DISPLAY_IME_POLICY_HIDE:
return "hide";
default:
assert(!"unexpected display IME policy");
return NULL;
}
}
static bool
validate_string(const char *s) {
// The parameters values are passed as command line arguments to adb, so
@@ -201,6 +183,27 @@ validate_string(const char *s) {
return true;
}
static uint16_t
get_device_sdk_version(struct sc_server *server) {
struct sc_intr *intr = &server->intr;
char *sdk_version =
sc_adb_getprop(intr, server->serial, "ro.build.version.sdk",
SC_ADB_SILENT);
if (!sdk_version) {
return 0;
}
long value;
bool ok = sc_str_parse_integer(sdk_version, &value);
free(sdk_version);
if (!ok || value < 0 || value > 0xFFFF) {
return 0;
}
return value;
}
static sc_pid
execute_server(struct sc_server *server,
const struct sc_server_params *params) {
@@ -219,7 +222,7 @@ execute_server(struct sc_server *server,
cmd[count++] = "app_process";
#ifdef SERVER_DEBUGGER
uint16_t sdk_version = sc_adb_get_device_sdk_version(&server->intr, serial);
uint16_t sdk_version = get_device_sdk_version(server);
if (!sdk_version) {
LOGE("Could not determine SDK version");
return 0;
@@ -231,15 +234,10 @@ execute_server(struct sc_server *server,
// Android < 9
dbg = "-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
SERVER_DEBUGGER_PORT;
} else if (sdk_version < 30) {
// Android >= 9 && Android < 11
} else {
// Android >= 9
dbg = "-XjdwpProvider:internal -XjdwpOptions:transport=dt_socket,"
"suspend=y,server=y,address=" SERVER_DEBUGGER_PORT;
} else {
// Android >= 11
// Contrary to the other methods, this does not suspend on start.
// <https://github.com/Genymobile/scrcpy/pull/5466>
dbg = "-XjdwpProvider:adbconnection";
}
cmd[count++] = dbg;
#endif
@@ -305,21 +303,9 @@ execute_server(struct sc_server *server,
VALIDATE_STRING(params->max_fps);
ADD_PARAM("max_fps=%s", params->max_fps);
}
if (params->angle) {
VALIDATE_STRING(params->angle);
ADD_PARAM("angle=%s", params->angle);
}
if (params->capture_orientation_lock != SC_ORIENTATION_UNLOCKED
|| params->capture_orientation != SC_ORIENTATION_0) {
if (params->capture_orientation_lock == SC_ORIENTATION_LOCKED_INITIAL) {
ADD_PARAM("capture_orientation=@");
} else {
const char *orient =
sc_orientation_get_name(params->capture_orientation);
bool locked =
params->capture_orientation_lock != SC_ORIENTATION_UNLOCKED;
ADD_PARAM("capture_orientation=%s%s", locked ? "@" : "", orient);
}
if (params->lock_video_orientation != SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
ADD_PARAM("lock_video_orientation=%" PRIi8,
params->lock_video_orientation);
}
if (server->tunnel.forward) {
ADD_PARAM("tunnel_forward=true");
@@ -407,16 +393,6 @@ execute_server(struct sc_server *server,
VALIDATE_STRING(params->new_display);
ADD_PARAM("new_display=%s", params->new_display);
}
if (params->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED) {
ADD_PARAM("display_ime_policy=%s",
sc_server_get_display_ime_policy_name(params->display_ime_policy));
}
if (!params->vd_destroy_content) {
ADD_PARAM("vd_destroy_content=false");
}
if (!params->vd_system_decorations) {
ADD_PARAM("vd_system_decorations=false");
}
if (params->list & SC_OPTION_LIST_ENCODERS) {
ADD_PARAM("list_encoders=true");
}
@@ -438,14 +414,10 @@ execute_server(struct sc_server *server,
cmd[count++] = NULL;
#ifdef SERVER_DEBUGGER
LOGI("Server debugger listening%s...",
sdk_version < 30 ? " on port " SERVER_DEBUGGER_PORT : "");
// For Android < 11, from the computer:
// - run `adb forward tcp:5005 tcp:5005`
// For Android >= 11:
// - execute `adb jdwp` to get the jdwp port
// - run `adb forward tcp:5005 jdwp:XXXX` (replace XXXX)
//
LOGI("Server debugger waiting for a client on device port "
SERVER_DEBUGGER_PORT "...");
// From the computer, run
// adb forward tcp:5005 tcp:5005
// Then, from Android Studio: Run > Debug > Edit configurations...
// On the left, click on '+', "Remote", with:
// Host: localhost
@@ -522,21 +494,14 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
// end of the program
server->params = *params;
bool ok = sc_adb_init();
bool ok = sc_mutex_init(&server->mutex);
if (!ok) {
return false;
}
ok = sc_mutex_init(&server->mutex);
if (!ok) {
sc_adb_destroy();
return false;
}
ok = sc_cond_init(&server->cond_stopped);
if (!ok) {
sc_mutex_destroy(&server->mutex);
sc_adb_destroy();
return false;
}
@@ -544,7 +509,6 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
if (!ok) {
sc_cond_destroy(&server->cond_stopped);
sc_mutex_destroy(&server->mutex);
sc_adb_destroy();
return false;
}
@@ -866,14 +830,11 @@ sc_server_switch_to_tcpip(struct sc_server *server, const char *serial) {
}
static bool
sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port,
bool disconnect) {
sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port) {
struct sc_intr *intr = &server->intr;
if (disconnect) {
// Error expected if not connected, do not report any error
sc_adb_disconnect(intr, ip_port, SC_ADB_SILENT);
}
// Error expected if not connected, do not report any error
sc_adb_disconnect(intr, ip_port, SC_ADB_SILENT);
LOGI("Connecting to %s...", ip_port);
@@ -889,7 +850,7 @@ sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port,
static bool
sc_server_configure_tcpip_known_address(struct sc_server *server,
const char *addr, bool disconnect) {
const char *addr) {
// Append ":5555" if no port is present
bool contains_port = strchr(addr, ':');
char *ip_port = contains_port ? strdup(addr)
@@ -900,7 +861,7 @@ sc_server_configure_tcpip_known_address(struct sc_server *server,
}
server->serial = ip_port;
return sc_server_connect_to_tcpip(server, ip_port, disconnect);
return sc_server_connect_to_tcpip(server, ip_port);
}
static bool
@@ -925,7 +886,7 @@ sc_server_configure_tcpip_unknown_address(struct sc_server *server,
}
server->serial = ip_port;
return sc_server_connect_to_tcpip(server, ip_port, false);
return sc_server_connect_to_tcpip(server, ip_port);
}
static void
@@ -1012,13 +973,7 @@ run_server(void *data) {
sc_adb_device_destroy(&device);
}
} else {
// If the user passed a '+' (--tcpip=+ip), then disconnect first
const char *tcpip_dst = params->tcpip_dst;
bool plus = tcpip_dst[0] == '+';
if (plus) {
++tcpip_dst;
}
ok = sc_server_configure_tcpip_known_address(server, tcpip_dst, plus);
ok = sc_server_configure_tcpip_known_address(server, params->tcpip_dst);
if (!ok) {
goto error_connection_failed;
}
@@ -1195,6 +1150,4 @@ sc_server_destroy(struct sc_server *server) {
sc_intr_destroy(&server->intr);
sc_cond_destroy(&server->cond_stopped);
sc_mutex_destroy(&server->mutex);
sc_adb_destroy();
}

View File

@@ -1,17 +1,19 @@
#ifndef SC_SERVER_H
#define SC_SERVER_H
#ifndef SERVER_H
#define SERVER_H
#include "common.h"
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include "adb/adb_tunnel.h"
#include "coords.h"
#include "options.h"
#include "util/intr.h"
#include "util/log.h"
#include "util/net.h"
#include "util/thread.h"
#include "util/tick.h"
#define SC_DEVICE_NAME_FIELD_LENGTH 64
struct sc_server_info {
@@ -43,14 +45,11 @@ struct sc_server_params {
uint32_t video_bit_rate;
uint32_t audio_bit_rate;
const char *max_fps; // float to be parsed by the server
const char *angle; // float to be parsed by the server
sc_tick screen_off_timeout;
enum sc_orientation capture_orientation;
enum sc_orientation_lock capture_orientation_lock;
int8_t lock_video_orientation;
bool control;
uint32_t display_id;
const char *new_display;
enum sc_display_ime_policy display_ime_policy;
bool video;
bool audio;
bool audio_dup;
@@ -68,8 +67,6 @@ struct sc_server_params {
bool power_on;
bool kill_adb_on_close;
bool camera_high_speed;
bool vd_destroy_content;
bool vd_system_decorations;
uint8_t list;
};

View File

@@ -3,7 +3,6 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <SDL2/SDL_keycode.h>

View File

@@ -1,15 +1,11 @@
#include "util/file.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __APPLE__
# include <mach-o/dyld.h> // for _NSGetExecutablePath()
#endif
#include "util/log.h"
@@ -64,22 +60,11 @@ sc_file_get_executable_path(void) {
}
buf[len] = '\0';
return strdup(buf);
#elif defined(__APPLE__)
char buf[PATH_MAX];
uint32_t bufsize = PATH_MAX;
if (_NSGetExecutablePath(buf, &bufsize) != 0) {
LOGE("Executable path buffer too small; need %u bytes", bufsize);
return NULL;
}
return realpath(buf, NULL);
#else
// "_" is often used to store the full path of the command being executed
char *path = getenv("_");
if (!path) {
LOGE("Could not determine executable path");
return NULL;
}
return strdup(path);
// in practice, we only need this feature for portable builds, only used on
// Windows, so we don't care implementing it for every platform
// (it's useful to have a working version on Linux for debugging though)
return NULL;
#endif
}

View File

@@ -4,8 +4,6 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include <libavcodec/avcodec.h>

View File

@@ -1,7 +1,5 @@
#include "frame_source.h"
#include <assert.h>
void
sc_frame_source_init(struct sc_frame_source *source) {
source->sink_count = 0;

View File

@@ -3,9 +3,7 @@
#include "common.h"
#include <stdbool.h>
#include "trait/frame_sink.h"
#include "frame_sink.h"
#define SC_FRAME_SOURCE_MAX_SINKS 2

View File

@@ -3,6 +3,9 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include "input_events.h"
/**
@@ -17,22 +20,13 @@ struct sc_gamepad_processor {
struct sc_gamepad_processor_ops {
/**
* Process a gamepad device added event
* Process a gamepad device added or removed
*
* This function is mandatory.
*/
void
(*process_gamepad_added)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event);
/**
* Process a gamepad device removed event
*
* This function is mandatory.
*/
void
(*process_gamepad_removed)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event);
(*process_gamepad_device)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event);
/**
* Process a gamepad axis event

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include "input_events.h"

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include "input_events.h"

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include <assert.h>
#include <stdbool.h>
#include <libavcodec/avcodec.h>

View File

@@ -1,7 +1,5 @@
#include "packet_source.h"
#include <assert.h>
void
sc_packet_source_init(struct sc_packet_source *source) {
source->sink_count = 0;

View File

@@ -3,9 +3,7 @@
#include "common.h"
#include <stdbool.h>
#include "trait/packet_sink.h"
#include "packet_sink.h"
#define SC_PACKET_SOURCE_MAX_SINKS 2

View File

@@ -1,10 +1,5 @@
#include "gamepad_uhid.h"
#include <assert.h>
#include <inttypes.h>
#include <string.h>
#include <SDL2/SDL_gamecontroller.h>
#include "hid/hid_gamepad.h"
#include "input_events.h"
#include "util/log.h"
@@ -12,11 +7,6 @@
/** Downcast gamepad processor to sc_gamepad_uhid */
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_uhid, gamepad_processor)
// Xbox 360
#define SC_GAMEPAD_UHID_VENDOR_ID UINT16_C(0x045e)
#define SC_GAMEPAD_UHID_PRODUCT_ID UINT16_C(0x028e)
#define SC_GAMEPAD_UHID_NAME "Microsoft X-Box 360 Pad"
static void
sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad,
const struct sc_hid_input *hid_input,
@@ -40,9 +30,7 @@ sc_gamepad_uhid_send_open(struct sc_gamepad_uhid *gamepad,
struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = hid_open->hid_id;
msg.uhid_create.vendor_id = SC_GAMEPAD_UHID_VENDOR_ID;
msg.uhid_create.product_id = SC_GAMEPAD_UHID_PRODUCT_ID;
msg.uhid_create.name = SC_GAMEPAD_UHID_NAME;
msg.uhid_create.name = hid_open->name;
msg.uhid_create.report_desc = hid_open->report_desc;
msg.uhid_create.report_desc_size = hid_open->report_desc_size;
@@ -64,39 +52,29 @@ sc_gamepad_uhid_send_close(struct sc_gamepad_uhid *gamepad,
}
static void
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
}
sc_gamepad_uhid_send_open(gamepad, &hid_open);
} else {
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
sc_gamepad_uhid_send_close(gamepad, &hid_close);
}
SDL_GameController* game_controller =
SDL_GameControllerFromInstanceID(event->gamepad_id);
assert(game_controller);
const char *name = SDL_GameControllerName(game_controller);
LOGI("Gamepad added: [%" PRIu32 "] %s", event->gamepad_id, name);
sc_gamepad_uhid_send_open(gamepad, &hid_open);
}
static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
LOGI("Gamepad removed: [%" PRIu32 "]", event->gamepad_id);
sc_gamepad_uhid_send_close(gamepad, &hid_close);
}
static void
@@ -136,8 +114,7 @@ sc_gamepad_uhid_init(struct sc_gamepad_uhid *gamepad,
gamepad->controller = controller;
static const struct sc_gamepad_processor_ops ops = {
.process_gamepad_added = sc_gamepad_processor_process_gamepad_added,
.process_gamepad_removed = sc_gamepad_processor_process_gamepad_removed,
.process_gamepad_device = sc_gamepad_processor_process_gamepad_device,
.process_gamepad_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button,
};

View File

@@ -3,6 +3,8 @@
#include "common.h"
#include <stdbool.h>
#include "controller.h"
#include "hid/hid_gamepad.h"
#include "trait/gamepad_processor.h"

View File

@@ -1,12 +1,6 @@
#include "keyboard_uhid.h"
#include <assert.h>
#include <string.h>
#include <SDL2/SDL_keyboard.h>
#include <SDL2/SDL_keycode.h>
#include "util/log.h"
#include "util/thread.h"
/** Downcast key processor to keyboard_uhid */
#define DOWNCAST(KP) container_of(KP, struct sc_keyboard_uhid, key_processor)
@@ -147,9 +141,7 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_KEYBOARD;
msg.uhid_create.vendor_id = 0;
msg.uhid_create.product_id = 0;
msg.uhid_create.name = NULL;
msg.uhid_create.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size;
if (!sc_controller_push_msg(controller, &msg)) {

View File

@@ -1,8 +1,5 @@
#include "mouse_uhid.h"
#include <assert.h>
#include <string.h>
#include "hid/hid_mouse.h"
#include "input_events.h"
#include "util/log.h"
@@ -55,9 +52,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
struct sc_mouse_uhid *mouse = DOWNCAST(mp);
struct sc_hid_input hid_input;
if (!sc_hid_mouse_generate_input_from_scroll(&hid_input, event)) {
return;
}
sc_hid_mouse_generate_input_from_scroll(&hid_input, event);
sc_mouse_uhid_send_input(mouse, &hid_input, "mouse scroll");
}
@@ -86,9 +81,7 @@ sc_mouse_uhid_init(struct sc_mouse_uhid *mouse,
struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_MOUSE;
msg.uhid_create.vendor_id = 0;
msg.uhid_create.product_id = 0;
msg.uhid_create.name = NULL;
msg.uhid_create.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size;
if (!sc_controller_push_msg(controller, &msg)) {

View File

@@ -1,5 +1,6 @@
#include "uhid_output.h"
#include <assert.h>
#include <inttypes.h>
#include "uhid/keyboard_uhid.h"

View File

@@ -3,7 +3,7 @@
#include "common.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
/**

View File

@@ -1,16 +1,13 @@
#include "aoa_hid.h"
#include "util/log.h"
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <libusb-1.0/libusb.h>
#include "aoa_hid.h"
#include "events.h"
#include "util/log.h"
#include "util/str.h"
#include "util/tick.h"
#include "util/vector.h"
// See <https://source.android.com/devices/accessories/aoa2#hid-support>.

View File

@@ -3,13 +3,16 @@
#include "common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdbool.h>
#include <libusb-1.0/libusb.h>
#include "hid/hid_event.h"
#include "usb/usb.h"
#include "usb.h"
#include "util/acksync.h"
#include "util/thread.h"
#include "util/tick.h"
#include "util/vecdeque.h"
enum sc_aoa_event_type {

View File

@@ -1,7 +1,5 @@
#include "gamepad_aoa.h"
#include <stdbool.h>
#include "input_events.h"
#include "util/log.h"
@@ -9,35 +7,33 @@
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_aoa, gamepad_processor)
static void
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
}
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
}
// exit_on_error: false (a gamepad open failure should not exit scrcpy)
if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) {
LOGW("Could not push AOA HID open (gamepad)");
}
}
// exit_on_error: false (a gamepad open failure should not exit scrcpy)
if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) {
LOGW("Could not push AOA HID open (gamepad)");
}
} else {
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
if (!sc_aoa_push_close(gamepad->aoa, &hid_close)) {
LOGW("Could not push AOA HID close (gamepad)");
if (!sc_aoa_push_close(gamepad->aoa, &hid_close)) {
LOGW("Could not push AOA HID close (gamepad)");
}
}
}
@@ -80,8 +76,7 @@ sc_gamepad_aoa_init(struct sc_gamepad_aoa *gamepad, struct sc_aoa *aoa) {
sc_hid_gamepad_init(&gamepad->hid);
static const struct sc_gamepad_processor_ops ops = {
.process_gamepad_added = sc_gamepad_processor_process_gamepad_added,
.process_gamepad_removed = sc_gamepad_processor_process_gamepad_removed,
.process_gamepad_device = sc_gamepad_processor_process_gamepad_device,
.process_gamepad_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button,
};

View File

@@ -3,8 +3,10 @@
#include "common.h"
#include <stdbool.h>
#include "aoa_hid.h"
#include "hid/hid_gamepad.h"
#include "usb/aoa_hid.h"
#include "trait/gamepad_processor.h"
struct sc_gamepad_aoa {

Some files were not shown because too many files have changed in this diff Show More