Compare commits
29 Commits
linux_maco
...
v3.0.2
Author | SHA1 | Date | |
---|---|---|---|
baa10ed0a3 | |||
2ed2247e8f | |||
5febb1e9fb | |||
5c3626ed47 | |||
0e473eb005 | |||
b26b4fb745 | |||
9555d3a537 | |||
aea6a371aa | |||
dc6c279b1e | |||
6d0ac3626d | |||
beee42fb06 | |||
131372d2c4 | |||
0fd7534bd5 | |||
36574d2ee7 | |||
3b2b3625e4 | |||
b2cdaa4bdc | |||
d01373c03c | |||
ff06b6dcc1 | |||
017a3672a4 | |||
c1351b250e | |||
618a978f5b | |||
acddd811bf | |||
ee9f7126ff | |||
a18ed1ee7a | |||
678025b316 | |||
3e689020ba | |||
3d1f036c04 | |||
3d5294c1e5 | |||
1d2f16dbb5 |
201
.github/workflows/release.yml
vendored
201
.github/workflows/release.yml
vendored
@ -42,10 +42,10 @@ jobs:
|
|||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
||||||
- name: Build scrcpy-server
|
- name: Build
|
||||||
run: release/build_server.sh
|
run: release/build_server.sh
|
||||||
|
|
||||||
- name: Upload scrcpy-server artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: scrcpy-server
|
name: scrcpy-server
|
||||||
@ -63,7 +63,7 @@ jobs:
|
|||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
||||||
- name: Build scrcpy-server without gradle
|
- name: Build without gradle
|
||||||
run: server/build_without_gradle.sh
|
run: server/build_without_gradle.sh
|
||||||
|
|
||||||
test-client:
|
test-client:
|
||||||
@ -74,7 +74,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||||
@ -83,36 +82,44 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
run: release/test_client.sh
|
run: release/test_client.sh
|
||||||
|
|
||||||
build-linux:
|
build-linux-x86_64:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Check architecture
|
||||||
|
run: |
|
||||||
|
arch=$(uname -m)
|
||||||
|
if [[ "$arch" != x86_64 ]]
|
||||||
|
then
|
||||||
|
echo "Unexpected architecture: $arch" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||||
libv4l-dev
|
libv4l-dev
|
||||||
|
|
||||||
- name: Build linux
|
- name: Build
|
||||||
run: release/build_linux.sh
|
run: release/build_linux.sh x86_64
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
- name: Tar
|
- name: Tar
|
||||||
run: |
|
run: |
|
||||||
cd release/work/build-linux
|
cd release/work/build-linux-x86_64
|
||||||
mkdir dist-tar
|
mkdir dist-tar
|
||||||
cd dist-tar
|
cd dist-tar
|
||||||
tar -C .. -cvf dist.tar.gz dist/
|
tar -C .. -cvf dist.tar.gz dist/
|
||||||
|
|
||||||
- name: Upload build-linux artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-linux-intermediate
|
name: build-linux-x86_64-intermediate
|
||||||
path: release/work/build-linux/dist-tar/
|
path: release/work/build-linux-x86_64/dist-tar/
|
||||||
|
|
||||||
build-win32:
|
build-win32:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -122,7 +129,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||||
@ -131,7 +137,7 @@ jobs:
|
|||||||
- name: Workaround for old meson version run by Github Actions
|
- name: Workaround for old meson version run by Github Actions
|
||||||
run: sed -i 's/^pkg-config/pkgconfig/' cross_win32.txt
|
run: sed -i 's/^pkg-config/pkgconfig/' cross_win32.txt
|
||||||
|
|
||||||
- name: Build win32
|
- name: Build
|
||||||
run: release/build_windows.sh 32
|
run: release/build_windows.sh 32
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
@ -142,7 +148,7 @@ jobs:
|
|||||||
cd dist-tar
|
cd dist-tar
|
||||||
tar -C .. -cvf dist.tar.gz dist/
|
tar -C .. -cvf dist.tar.gz dist/
|
||||||
|
|
||||||
- name: Upload build-win32 artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-win32-intermediate
|
name: build-win32-intermediate
|
||||||
@ -156,7 +162,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||||
@ -165,7 +170,7 @@ jobs:
|
|||||||
- name: Workaround for old meson version run by Github Actions
|
- name: Workaround for old meson version run by Github Actions
|
||||||
run: sed -i 's/^pkg-config/pkgconfig/' cross_win64.txt
|
run: sed -i 's/^pkg-config/pkgconfig/' cross_win64.txt
|
||||||
|
|
||||||
- name: Build win64
|
- name: Build
|
||||||
run: release/build_windows.sh 64
|
run: release/build_windows.sh 64
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
@ -176,15 +181,24 @@ jobs:
|
|||||||
cd dist-tar
|
cd dist-tar
|
||||||
tar -C .. -cvf dist.tar.gz dist/
|
tar -C .. -cvf dist.tar.gz dist/
|
||||||
|
|
||||||
- name: Upload build-win64 artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-win64-intermediate
|
name: build-win64-intermediate
|
||||||
path: release/work/build-win64/dist-tar/
|
path: release/work/build-win64/dist-tar/
|
||||||
|
|
||||||
build-macos:
|
build-macos-aarch64:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Check architecture
|
||||||
|
run: |
|
||||||
|
arch=$(uname -m)
|
||||||
|
if [[ "$arch" != arm64 ]]
|
||||||
|
then
|
||||||
|
echo "Unexpected architecture: $arch" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
@ -193,27 +207,63 @@ jobs:
|
|||||||
brew install meson ninja nasm libiconv zlib automake autoconf \
|
brew install meson ninja nasm libiconv zlib automake autoconf \
|
||||||
libtool
|
libtool
|
||||||
|
|
||||||
- name: Build macOS
|
- name: Build
|
||||||
run: release/build_macos.sh
|
run: release/build_macos.sh aarch64
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
- name: Tar
|
- name: Tar
|
||||||
run: |
|
run: |
|
||||||
cd release/work/build-macos
|
cd release/work/build-macos-aarch64
|
||||||
mkdir dist-tar
|
mkdir dist-tar
|
||||||
cd dist-tar
|
cd dist-tar
|
||||||
tar -C .. -cvf dist.tar.gz dist/
|
tar -C .. -cvf dist.tar.gz dist/
|
||||||
|
|
||||||
- name: Upload build-macos artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-macos-intermediate
|
name: build-macos-aarch64-intermediate
|
||||||
path: release/work/build-macos/dist-tar/
|
path: release/work/build-macos-aarch64/dist-tar/
|
||||||
|
|
||||||
package-linux:
|
build-macos-x86_64:
|
||||||
|
runs-on: macos-13
|
||||||
|
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 ninja nasm libiconv zlib automake
|
||||||
|
# autoconf and libtool are already installed on macos-13
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
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:
|
needs:
|
||||||
- build-scrcpy-server
|
- build-scrcpy-server
|
||||||
- build-linux
|
- build-linux-x86_64
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@ -225,25 +275,25 @@ jobs:
|
|||||||
name: scrcpy-server
|
name: scrcpy-server
|
||||||
path: release/work/build-server/server/
|
path: release/work/build-server/server/
|
||||||
|
|
||||||
- name: Download build-linux
|
- name: Download build-linux-x86_64
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-linux-intermediate
|
name: build-linux-x86_64-intermediate
|
||||||
path: release/work/build-linux/dist-tar/
|
path: release/work/build-linux-x86_64/dist-tar/
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
- name: Detar
|
- name: Detar
|
||||||
run: |
|
run: |
|
||||||
cd release/work/build-linux
|
cd release/work/build-linux-x86_64
|
||||||
tar xf dist-tar/dist.tar.gz
|
tar xf dist-tar/dist.tar.gz
|
||||||
|
|
||||||
- name: Package linux
|
- name: Package
|
||||||
run: release/package_client.sh linux tar.gz
|
run: release/package_client.sh linux-x86_64 tar.gz
|
||||||
|
|
||||||
- name: Upload linux release
|
- name: Upload release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-linux
|
name: release-linux-x86_64
|
||||||
path: release/output/
|
path: release/output/
|
||||||
|
|
||||||
package-win32:
|
package-win32:
|
||||||
@ -273,10 +323,10 @@ jobs:
|
|||||||
cd release/work/build-win32
|
cd release/work/build-win32
|
||||||
tar xf dist-tar/dist.tar.gz
|
tar xf dist-tar/dist.tar.gz
|
||||||
|
|
||||||
- name: Package win32
|
- name: Package
|
||||||
run: release/package_client.sh win32 zip
|
run: release/package_client.sh win32 zip
|
||||||
|
|
||||||
- name: Upload win32 release
|
- name: Upload release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-win32
|
name: release-win32
|
||||||
@ -309,19 +359,55 @@ jobs:
|
|||||||
cd release/work/build-win64
|
cd release/work/build-win64
|
||||||
tar xf dist-tar/dist.tar.gz
|
tar xf dist-tar/dist.tar.gz
|
||||||
|
|
||||||
- name: Package win64
|
- name: Package
|
||||||
run: release/package_client.sh win64 zip
|
run: release/package_client.sh win64 zip
|
||||||
|
|
||||||
- name: Upload win64 release
|
- name: Upload release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-win64
|
name: release-win64
|
||||||
path: release/output
|
path: release/output
|
||||||
|
|
||||||
package-macos:
|
package-macos-aarch64:
|
||||||
needs:
|
needs:
|
||||||
- build-scrcpy-server
|
- build-scrcpy-server
|
||||||
- build-macos
|
- 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
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@ -336,31 +422,32 @@ jobs:
|
|||||||
- name: Download build-macos
|
- name: Download build-macos
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-macos-intermediate
|
name: build-macos-x86_64-intermediate
|
||||||
path: release/work/build-macos/dist-tar/
|
path: release/work/build-macos-x86_64/dist-tar/
|
||||||
|
|
||||||
# upload-artifact does not preserve permissions
|
# upload-artifact does not preserve permissions
|
||||||
- name: Detar
|
- name: Detar
|
||||||
run: |
|
run: |
|
||||||
cd release/work/build-macos
|
cd release/work/build-macos-x86_64
|
||||||
tar xf dist-tar/dist.tar.gz
|
tar xf dist-tar/dist.tar.gz
|
||||||
|
|
||||||
- name: Package macos
|
- name: Package
|
||||||
run: release/package_client.sh macos tar.gz
|
run: release/package_client.sh macos-x86_64 tar.gz
|
||||||
|
|
||||||
- name: Upload macos release
|
- name: Upload release
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-macos
|
name: release-macos-x86_64
|
||||||
path: release/output/
|
path: release/output/
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs:
|
needs:
|
||||||
- build-scrcpy-server
|
- build-scrcpy-server
|
||||||
- package-linux
|
- package-linux-x86_64
|
||||||
- package-win32
|
- package-win32
|
||||||
- package-win64
|
- package-win64
|
||||||
- package-macos
|
- package-macos-aarch64
|
||||||
|
- package-macos-x86_64
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@ -372,10 +459,10 @@ jobs:
|
|||||||
name: scrcpy-server
|
name: scrcpy-server
|
||||||
path: release/work/build-server/server/
|
path: release/work/build-server/server/
|
||||||
|
|
||||||
- name: Download release-linux
|
- name: Download release-linux-x86_64
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-linux
|
name: release-linux-x86_64
|
||||||
path: release/output/
|
path: release/output/
|
||||||
|
|
||||||
- name: Download release-win32
|
- name: Download release-win32
|
||||||
@ -390,10 +477,16 @@ jobs:
|
|||||||
name: release-win64
|
name: release-win64
|
||||||
path: release/output/
|
path: release/output/
|
||||||
|
|
||||||
- name: Download release-macos
|
- name: Download release-macos-aarch64
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: release-macos
|
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/
|
path: release/output/
|
||||||
|
|
||||||
- name: Package server
|
- name: Package server
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
source for the project. Do not download releases from random websites, even if
|
source for the project. Do not download releases from random websites, even if
|
||||||
their name contains `scrcpy`.**
|
their name contains `scrcpy`.**
|
||||||
|
|
||||||
# scrcpy (v3.0)
|
# scrcpy (v3.0.2)
|
||||||
|
|
||||||
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
|
||||||
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
cd "$(dirname ${BASH_SOURCE[0]})"
|
|
||||||
export ADB="${ADB:-./adb}"
|
|
||||||
export SCRCPY_SERVER_PATH="${SCRCPY_SERVER_PATH:-./scrcpy-server}"
|
|
||||||
export SCRCPY_ICON_PATH="${SCRCPY_ICON_PATH:-./icon.png}"
|
|
||||||
./scrcpy_bin "$@"
|
|
@ -46,6 +46,7 @@ src = [
|
|||||||
'src/util/acksync.c',
|
'src/util/acksync.c',
|
||||||
'src/util/audiobuf.c',
|
'src/util/audiobuf.c',
|
||||||
'src/util/average.c',
|
'src/util/average.c',
|
||||||
|
'src/util/env.c',
|
||||||
'src/util/file.c',
|
'src/util/file.c',
|
||||||
'src/util/intmap.c',
|
'src/util/intmap.c',
|
||||||
'src/util/intr.c',
|
'src/util/intr.c',
|
||||||
|
@ -13,7 +13,7 @@ BEGIN
|
|||||||
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
VALUE "LegalCopyright", "Romain Vimont, Genymobile"
|
||||||
VALUE "OriginalFilename", "scrcpy.exe"
|
VALUE "OriginalFilename", "scrcpy.exe"
|
||||||
VALUE "ProductName", "scrcpy"
|
VALUE "ProductName", "scrcpy"
|
||||||
VALUE "ProductVersion", "3.0"
|
VALUE "ProductVersion", "3.0.2"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -518,13 +518,15 @@ Enable "show touches" on start, restore the initial value on exit.
|
|||||||
It only shows physical touches (not clicks from scrcpy).
|
It only shows physical touches (not clicks from scrcpy).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-tcpip\fR[=\fIip\fR[:\fIport\fR]]
|
.BI "\-\-tcpip\fR[=[+]\fIip\fR[:\fIport\fR]]
|
||||||
Configure and reconnect the device over TCP/IP.
|
Configure and connect 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 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.
|
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
|
.TP
|
||||||
.BI "\-\-time\-limit " seconds
|
.BI "\-\-time\-limit " seconds
|
||||||
Set the maximum mirroring time, in seconds.
|
Set the maximum mirroring time, in seconds.
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "adb_device.h"
|
#include "adb_device.h"
|
||||||
#include "adb_parser.h"
|
#include "adb_parser.h"
|
||||||
|
#include "util/env.h"
|
||||||
#include "util/file.h"
|
#include "util/file.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/process_intr.h"
|
#include "util/process_intr.h"
|
||||||
@ -24,15 +25,45 @@
|
|||||||
*/
|
*/
|
||||||
#define SC_ADB_COMMAND(...) { sc_adb_get_executable(), __VA_ARGS__, NULL }
|
#define SC_ADB_COMMAND(...) { sc_adb_get_executable(), __VA_ARGS__, NULL }
|
||||||
|
|
||||||
static const char *adb_executable;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
sc_adb_get_executable(void) {
|
sc_adb_get_executable(void) {
|
||||||
if (!adb_executable) {
|
|
||||||
adb_executable = getenv("ADB");
|
|
||||||
if (!adb_executable)
|
|
||||||
adb_executable = "adb";
|
|
||||||
}
|
|
||||||
return adb_executable;
|
return adb_executable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +412,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
|
// "adb connect" always returns successfully (with exit code 0), even in
|
||||||
// case of failure. As a workaround, check if its output starts with
|
// case of failure. As a workaround, check if its output starts with
|
||||||
// "connected".
|
// "connected" or "already connected".
|
||||||
char buf[128];
|
char buf[128];
|
||||||
ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
|
ssize_t r = sc_pipe_read_all_intr(intr, pid, pout, buf, sizeof(buf) - 1);
|
||||||
sc_pipe_close(pout);
|
sc_pipe_close(pout);
|
||||||
@ -398,7 +429,8 @@ sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags) {
|
|||||||
assert((size_t) r < sizeof(buf));
|
assert((size_t) r < sizeof(buf));
|
||||||
buf[r] = '\0';
|
buf[r] = '\0';
|
||||||
|
|
||||||
ok = !strncmp("connected", buf, sizeof("connected") - 1);
|
ok = !strncmp("connected", buf, sizeof("connected") - 1)
|
||||||
|
|| !strncmp("already connected", buf, sizeof("already connected") - 1);
|
||||||
if (!ok && !(flags & SC_ADB_NO_STDERR)) {
|
if (!ok && !(flags & SC_ADB_NO_STDERR)) {
|
||||||
// "adb connect" also prints errors to stdout. Since we capture it,
|
// "adb connect" also prints errors to stdout. Since we capture it,
|
||||||
// re-print the error to stderr.
|
// re-print the error to stderr.
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)
|
#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 *
|
const char *
|
||||||
sc_adb_get_executable(void);
|
sc_adb_get_executable(void);
|
||||||
|
|
||||||
|
@ -860,16 +860,17 @@ static const struct sc_option options[] = {
|
|||||||
{
|
{
|
||||||
.longopt_id = OPT_TCPIP,
|
.longopt_id = OPT_TCPIP,
|
||||||
.longopt = "tcpip",
|
.longopt = "tcpip",
|
||||||
.argdesc = "ip[:port]",
|
.argdesc = "[+]ip[:port]",
|
||||||
.optional_arg = true,
|
.optional_arg = true,
|
||||||
.text = "Configure and reconnect the device over TCP/IP.\n"
|
.text = "Configure and connect the device over TCP/IP.\n"
|
||||||
"If a destination address is provided, then scrcpy connects to "
|
"If a destination address is provided, then scrcpy connects to "
|
||||||
"this address before starting. The device must listen on the "
|
"this address before starting. The device must listen on the "
|
||||||
"given TCP port (default is 5555).\n"
|
"given TCP port (default is 5555).\n"
|
||||||
"If no destination address is provided, then scrcpy attempts "
|
"If no destination address is provided, then scrcpy attempts "
|
||||||
"to find the IP address of the current device (typically "
|
"to find the IP address of the current device (typically "
|
||||||
"connected over USB), enables TCP/IP mode, then connects to "
|
"connected over USB), enables TCP/IP mode, then connects to "
|
||||||
"this address before starting.",
|
"this address before starting.\n"
|
||||||
|
"Prefix the address with a '+' to force a reconnection.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.longopt_id = OPT_TIME_LIMIT,
|
.longopt_id = OPT_TIME_LIMIT,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
#include "util/env.h"
|
||||||
#include "util/file.h"
|
#include "util/file.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/str.h"
|
#include "util/str.h"
|
||||||
@ -19,35 +20,22 @@
|
|||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_icon_path(void) {
|
get_icon_path(void) {
|
||||||
#ifdef __WINDOWS__
|
char *icon_path = sc_get_env("SCRCPY_ICON_PATH");
|
||||||
const wchar_t *icon_path_env = _wgetenv(L"SCRCPY_ICON_PATH");
|
if (icon_path) {
|
||||||
#else
|
|
||||||
const char *icon_path_env = getenv("SCRCPY_ICON_PATH");
|
|
||||||
#endif
|
|
||||||
if (icon_path_env) {
|
|
||||||
// if the envvar is set, use it
|
// 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);
|
LOGD("Using SCRCPY_ICON_PATH: %s", icon_path);
|
||||||
return icon_path;
|
return icon_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PORTABLE
|
#ifndef PORTABLE
|
||||||
LOGD("Using icon: " SCRCPY_DEFAULT_ICON_PATH);
|
LOGD("Using icon: " SCRCPY_DEFAULT_ICON_PATH);
|
||||||
char *icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
|
icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
|
||||||
if (!icon_path) {
|
if (!icon_path) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
char *icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
|
icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
|
||||||
if (!icon_path) {
|
if (!icon_path) {
|
||||||
LOGE("Could not get icon path");
|
LOGE("Could not get icon path");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "adb/adb.h"
|
#include "adb/adb.h"
|
||||||
#include "util/binary.h"
|
#include "util/binary.h"
|
||||||
|
#include "util/env.h"
|
||||||
#include "util/file.h"
|
#include "util/file.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net_intr.h"
|
#include "util/net_intr.h"
|
||||||
@ -25,35 +26,22 @@
|
|||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_server_path(void) {
|
get_server_path(void) {
|
||||||
#ifdef __WINDOWS__
|
char *server_path = sc_get_env("SCRCPY_SERVER_PATH");
|
||||||
const wchar_t *server_path_env = _wgetenv(L"SCRCPY_SERVER_PATH");
|
if (server_path) {
|
||||||
#else
|
|
||||||
const char *server_path_env = getenv("SCRCPY_SERVER_PATH");
|
|
||||||
#endif
|
|
||||||
if (server_path_env) {
|
|
||||||
// if the envvar is set, use it
|
// 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);
|
LOGD("Using SCRCPY_SERVER_PATH: %s", server_path);
|
||||||
return server_path;
|
return server_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PORTABLE
|
#ifndef PORTABLE
|
||||||
LOGD("Using server: " SC_SERVER_PATH_DEFAULT);
|
LOGD("Using server: " SC_SERVER_PATH_DEFAULT);
|
||||||
char *server_path = strdup(SC_SERVER_PATH_DEFAULT);
|
server_path = strdup(SC_SERVER_PATH_DEFAULT);
|
||||||
if (!server_path) {
|
if (!server_path) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
char *server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
|
server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
|
||||||
if (!server_path) {
|
if (!server_path) {
|
||||||
LOGE("Could not get local file path, "
|
LOGE("Could not get local file path, "
|
||||||
"using " SC_SERVER_FILENAME " from current directory");
|
"using " SC_SERVER_FILENAME " from current directory");
|
||||||
@ -497,14 +485,21 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
|||||||
// end of the program
|
// end of the program
|
||||||
server->params = *params;
|
server->params = *params;
|
||||||
|
|
||||||
bool ok = sc_mutex_init(&server->mutex);
|
bool ok = sc_adb_init();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ok = sc_mutex_init(&server->mutex);
|
||||||
|
if (!ok) {
|
||||||
|
sc_adb_destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ok = sc_cond_init(&server->cond_stopped);
|
ok = sc_cond_init(&server->cond_stopped);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
sc_mutex_destroy(&server->mutex);
|
sc_mutex_destroy(&server->mutex);
|
||||||
|
sc_adb_destroy();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,6 +507,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
sc_cond_destroy(&server->cond_stopped);
|
sc_cond_destroy(&server->cond_stopped);
|
||||||
sc_mutex_destroy(&server->mutex);
|
sc_mutex_destroy(&server->mutex);
|
||||||
|
sc_adb_destroy();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,11 +829,14 @@ sc_server_switch_to_tcpip(struct sc_server *server, const char *serial) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port) {
|
sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port,
|
||||||
|
bool disconnect) {
|
||||||
struct sc_intr *intr = &server->intr;
|
struct sc_intr *intr = &server->intr;
|
||||||
|
|
||||||
// Error expected if not connected, do not report any error
|
if (disconnect) {
|
||||||
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);
|
LOGI("Connecting to %s...", ip_port);
|
||||||
|
|
||||||
@ -853,7 +852,7 @@ sc_server_connect_to_tcpip(struct sc_server *server, const char *ip_port) {
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
sc_server_configure_tcpip_known_address(struct sc_server *server,
|
sc_server_configure_tcpip_known_address(struct sc_server *server,
|
||||||
const char *addr) {
|
const char *addr, bool disconnect) {
|
||||||
// Append ":5555" if no port is present
|
// Append ":5555" if no port is present
|
||||||
bool contains_port = strchr(addr, ':');
|
bool contains_port = strchr(addr, ':');
|
||||||
char *ip_port = contains_port ? strdup(addr)
|
char *ip_port = contains_port ? strdup(addr)
|
||||||
@ -864,7 +863,7 @@ sc_server_configure_tcpip_known_address(struct sc_server *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
server->serial = ip_port;
|
server->serial = ip_port;
|
||||||
return sc_server_connect_to_tcpip(server, ip_port);
|
return sc_server_connect_to_tcpip(server, ip_port, disconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -889,7 +888,7 @@ sc_server_configure_tcpip_unknown_address(struct sc_server *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
server->serial = ip_port;
|
server->serial = ip_port;
|
||||||
return sc_server_connect_to_tcpip(server, ip_port);
|
return sc_server_connect_to_tcpip(server, ip_port, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -976,7 +975,13 @@ run_server(void *data) {
|
|||||||
sc_adb_device_destroy(&device);
|
sc_adb_device_destroy(&device);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ok = sc_server_configure_tcpip_known_address(server, params->tcpip_dst);
|
// 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);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
@ -1153,4 +1158,6 @@ sc_server_destroy(struct sc_server *server) {
|
|||||||
sc_intr_destroy(&server->intr);
|
sc_intr_destroy(&server->intr);
|
||||||
sc_cond_destroy(&server->cond_stopped);
|
sc_cond_destroy(&server->cond_stopped);
|
||||||
sc_mutex_destroy(&server->mutex);
|
sc_mutex_destroy(&server->mutex);
|
||||||
|
|
||||||
|
sc_adb_destroy();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# include <mach-o/dyld.h> // for _NSGetExecutablePath()
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
@ -60,11 +63,22 @@ sc_file_get_executable_path(void) {
|
|||||||
}
|
}
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
return strdup(buf);
|
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
|
#else
|
||||||
// in practice, we only need this feature for portable builds, only used on
|
// "_" is often used to store the full path of the command being executed
|
||||||
// Windows, so we don't care implementing it for every platform
|
char *path = getenv("_");
|
||||||
// (it's useful to have a working version on Linux for debugging though)
|
if (!path) {
|
||||||
return NULL;
|
LOGE("Could not determine executable path");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return strdup(path);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +95,14 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
// On Windows, only one process could open a USB device
|
// On Windows, only one process could open a USB device
|
||||||
// <https://github.com/Genymobile/scrcpy/issues/2773>
|
// <https://github.com/Genymobile/scrcpy/issues/2773>
|
||||||
LOGI("Killing adb server (if any)...");
|
LOGI("Killing adb server (if any)...");
|
||||||
unsigned flags = SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR;
|
if (sc_adb_init()) {
|
||||||
// uninterruptible (intr == NULL), but in practice it's very quick
|
unsigned flags = SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR;
|
||||||
sc_adb_kill_server(NULL, flags);
|
// uninterruptible (intr == NULL), but in practice it's very quick
|
||||||
|
sc_adb_kill_server(NULL, flags);
|
||||||
|
sc_adb_destroy();
|
||||||
|
} else {
|
||||||
|
LOGW("Could not call adb executable, adb server not killed");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct sc_usb_callbacks cbs = {
|
static const struct sc_usb_callbacks cbs = {
|
||||||
|
29
app/src/util/env.c
Normal file
29
app/src/util/env.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "util/str.h"
|
||||||
|
|
||||||
|
char *
|
||||||
|
sc_get_env(const char *varname) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t *w_varname = sc_str_to_wchars(varname);
|
||||||
|
if (!w_varname) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const wchar_t *value = _wgetenv(w_varname);
|
||||||
|
free(w_varname);
|
||||||
|
if (!value) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sc_str_from_wchars(value);
|
||||||
|
#else
|
||||||
|
const char *value = getenv(varname);
|
||||||
|
if (!value) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strdup(value);
|
||||||
|
#endif
|
||||||
|
}
|
12
app/src/util/env.h
Normal file
12
app/src/util/env.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef SC_ENV_H
|
||||||
|
#define SC_ENV_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
// Return the value of the environment variable (may be NULL).
|
||||||
|
//
|
||||||
|
// The returned value must be freed by the caller.
|
||||||
|
char *
|
||||||
|
sc_get_env(const char *varname);
|
||||||
|
|
||||||
|
#endif
|
@ -9,8 +9,6 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <ws2tcpip.h>
|
# include <ws2tcpip.h>
|
||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
typedef SOCKET sc_raw_socket;
|
|
||||||
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
|
|
||||||
#else
|
#else
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
@ -23,8 +21,6 @@
|
|||||||
typedef struct sockaddr_in SOCKADDR_IN;
|
typedef struct sockaddr_in SOCKADDR_IN;
|
||||||
typedef struct sockaddr SOCKADDR;
|
typedef struct sockaddr SOCKADDR;
|
||||||
typedef struct in_addr IN_ADDR;
|
typedef struct in_addr IN_ADDR;
|
||||||
typedef int sc_raw_socket;
|
|
||||||
# define SC_RAW_SOCKET_NONE -1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -47,17 +43,26 @@ net_cleanup(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
sc_raw_socket_close(sc_raw_socket raw_sock) {
|
||||||
|
#ifndef _WIN32
|
||||||
|
return !close(raw_sock);
|
||||||
|
#else
|
||||||
|
return !closesocket(raw_sock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline sc_socket
|
static inline sc_socket
|
||||||
wrap(sc_raw_socket sock) {
|
wrap(sc_raw_socket sock) {
|
||||||
#ifdef _WIN32
|
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
if (sock == INVALID_SOCKET) {
|
if (sock == SC_RAW_SOCKET_NONE) {
|
||||||
return SC_SOCKET_NONE;
|
return SC_SOCKET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sc_socket_windows *socket = malloc(sizeof(*socket));
|
struct sc_socket_wrapper *socket = malloc(sizeof(*socket));
|
||||||
if (!socket) {
|
if (!socket) {
|
||||||
LOG_OOM();
|
LOG_OOM();
|
||||||
closesocket(sock);
|
sc_raw_socket_close(sock);
|
||||||
return SC_SOCKET_NONE;
|
return SC_SOCKET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +77,9 @@ wrap(sc_raw_socket sock) {
|
|||||||
|
|
||||||
static inline sc_raw_socket
|
static inline sc_raw_socket
|
||||||
unwrap(sc_socket socket) {
|
unwrap(sc_socket socket) {
|
||||||
#ifdef _WIN32
|
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
if (socket == SC_SOCKET_NONE) {
|
if (socket == SC_SOCKET_NONE) {
|
||||||
return INVALID_SOCKET;
|
return SC_RAW_SOCKET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return socket->socket;
|
return socket->socket;
|
||||||
@ -83,17 +88,6 @@ unwrap(sc_socket socket) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_SOCK_CLOEXEC // avoid unused-function warning
|
|
||||||
static inline bool
|
|
||||||
sc_raw_socket_close(sc_raw_socket raw_sock) {
|
|
||||||
#ifndef _WIN32
|
|
||||||
return !close(raw_sock);
|
|
||||||
#else
|
|
||||||
return !closesocket(raw_sock);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_SOCK_CLOEXEC
|
#ifndef HAVE_SOCK_CLOEXEC
|
||||||
// If SOCK_CLOEXEC does not exist, the flag must be set manually once the
|
// If SOCK_CLOEXEC does not exist, the flag must be set manually once the
|
||||||
// socket is created
|
// socket is created
|
||||||
@ -248,9 +242,9 @@ net_interrupt(sc_socket socket) {
|
|||||||
|
|
||||||
sc_raw_socket raw_sock = unwrap(socket);
|
sc_raw_socket raw_sock = unwrap(socket);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
if (!atomic_flag_test_and_set(&socket->closed)) {
|
if (!atomic_flag_test_and_set(&socket->closed)) {
|
||||||
return !closesocket(raw_sock);
|
return sc_raw_socket_close(raw_sock);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
@ -262,15 +256,15 @@ bool
|
|||||||
net_close(sc_socket socket) {
|
net_close(sc_socket socket) {
|
||||||
sc_raw_socket raw_sock = unwrap(socket);
|
sc_raw_socket raw_sock = unwrap(socket);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
if (!atomic_flag_test_and_set(&socket->closed)) {
|
if (!atomic_flag_test_and_set(&socket->closed)) {
|
||||||
ret = !closesocket(raw_sock);
|
ret = sc_raw_socket_close(raw_sock);
|
||||||
}
|
}
|
||||||
free(socket);
|
free(socket);
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
return !close(raw_sock);
|
return sc_raw_socket_close(raw_sock);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,21 +7,36 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
|
typedef SOCKET sc_raw_socket;
|
||||||
|
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
|
||||||
|
#else // not _WIN32
|
||||||
|
# include <sys/socket.h>
|
||||||
|
typedef int sc_raw_socket;
|
||||||
|
# define SC_RAW_SOCKET_NONE -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__APPLE__)
|
||||||
|
// On Windows and macOS, shutdown() does not interrupt accept() or read()
|
||||||
|
// calls, so net_interrupt() must call close() instead, and net_close() must
|
||||||
|
// behave accordingly.
|
||||||
|
// This causes a small race condition (once the socket is closed, its
|
||||||
|
// handle becomes invalid and may in theory be reassigned before another
|
||||||
|
// thread calls accept() or read()), but it is deemed acceptable as a
|
||||||
|
// workaround.
|
||||||
|
# define SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
|
||||||
# include <stdatomic.h>
|
# include <stdatomic.h>
|
||||||
# define SC_SOCKET_NONE NULL
|
# define SC_SOCKET_NONE NULL
|
||||||
typedef struct sc_socket_windows {
|
typedef struct sc_socket_wrapper {
|
||||||
SOCKET socket;
|
sc_raw_socket socket;
|
||||||
atomic_flag closed;
|
atomic_flag closed;
|
||||||
} *sc_socket;
|
} *sc_socket;
|
||||||
|
#else
|
||||||
#else // not _WIN32
|
|
||||||
|
|
||||||
# include <sys/socket.h>
|
|
||||||
# define SC_SOCKET_NONE -1
|
# define SC_SOCKET_NONE -1
|
||||||
typedef int sc_socket;
|
typedef sc_raw_socket sc_socket;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IPV4_LOCALHOST 0x7F000001
|
#define IPV4_LOCALHOST 0x7F000001
|
||||||
|
@ -233,10 +233,10 @@ install` must be run as root)._
|
|||||||
|
|
||||||
#### Option 2: Use prebuilt server
|
#### Option 2: Use prebuilt server
|
||||||
|
|
||||||
- [`scrcpy-server-v3.0`][direct-scrcpy-server]
|
- [`scrcpy-server-v3.0.2`][direct-scrcpy-server]
|
||||||
<sub>SHA-256: `800044c62a94d5fc16f5ab9c86d45b1050eae3eb436514d1b0d2fe2646b894ea`</sub>
|
<sub>SHA-256: `e19fe024bfa3367809494407ad6ca809a6f6e77dac95e99f85ba75144e0ba35d`</sub>
|
||||||
|
|
||||||
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-server-v3.0
|
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-server-v3.0.2
|
||||||
|
|
||||||
Download the prebuilt server somewhere, and specify its path during the Meson
|
Download the prebuilt server somewhere, and specify its path during the Meson
|
||||||
configuration:
|
configuration:
|
||||||
|
@ -85,6 +85,12 @@ scrcpy --tcpip=192.168.1.1 # default port is 5555
|
|||||||
scrcpy --tcpip=192.168.1.1:5555
|
scrcpy --tcpip=192.168.1.1:5555
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Prefix the address with a '+' to force a reconnection:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --tcpip=+192.168.1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Manual
|
### Manual
|
||||||
|
|
||||||
|
@ -23,14 +23,20 @@ To control the device without mirroring:
|
|||||||
scrcpy --no-video --no-audio
|
scrcpy --no-video --no-audio
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, mouse mode is switched to UHID if video mirroring is disabled (a
|
By default, the mouse is disabled when video playback is turned off.
|
||||||
relative mouse mode is required).
|
|
||||||
|
To control the device using a relative mouse, enable UHID mouse mode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --no-video --no-audio --mouse=uhid
|
||||||
|
scrcpy --no-video --no-audio -M # short version
|
||||||
|
```
|
||||||
|
|
||||||
To also use a UHID keyboard, set it explicitly:
|
To also use a UHID keyboard, set it explicitly:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scrcpy --no-video --no-audio --keyboard=uhid
|
scrcpy --no-video --no-audio --mouse=uhid --keyboard=uhid
|
||||||
scrcpy --no-video --no-audio -K # short version
|
scrcpy --no-video --no-audio -MK # short version
|
||||||
```
|
```
|
||||||
|
|
||||||
To use AOA instead (over USB only):
|
To use AOA instead (over USB only):
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
Download a static build of the [latest release]:
|
Download a static build of the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-linux-v3.0.tar.gz`][direct-linux] (x86_64)
|
- [`scrcpy-linux-x86_64-v3.0.2.tar.gz`][direct-linux-x86_64] (x86_64)
|
||||||
<sub>SHA-256: `06cb74e22f758228c944cea048b78e42b2925c2affe2b5aca901cfd6a649e503`</sub>
|
<sub>SHA-256: `20b69dcd379bb7d7208bf1e4858cf04162fc856697be0e6c03863d7b3c1e734a`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-linux]: https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-linux-v3.0.tar.gz
|
[direct-linux-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-linux-x86_64-v3.0.2.tar.gz
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
10
doc/macos.md
10
doc/macos.md
@ -6,11 +6,15 @@
|
|||||||
|
|
||||||
Download a static build of the [latest release]:
|
Download a static build of the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-macos-v3.0.tar.gz`][direct-macos] (arm64)
|
- [`scrcpy-macos-aarch64-v3.0.2.tar.gz`][direct-macos-aarch64] (aarch64)
|
||||||
<sub>SHA-256: `5db9821918537eb3aaf0333cdd05baf85babdd851972d5f1b71f86da0530b4bf`</sub>
|
<sub>SHA-256: `811ba2f4e856146bdd161e24c3490d78efbec2339ca783fac791d041c0aecfb6`</sub>
|
||||||
|
|
||||||
|
- [`scrcpy-macos-x86_64-v3.0.2.tar.gz`][direct-macos-x86_64] (x86_64)
|
||||||
|
<sub>SHA-256: `8effff54dca3a3e46eaaec242771a13a7f81af2e18670b3d0d8ed6b461bb4f79`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-macos]: https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-macos-v3.0.tar.gz
|
[direct-macos-aarch64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-macos-aarch64-v3.0.2.tar.gz
|
||||||
|
[direct-macos-x86_64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-macos-x86_64-v3.0.2.tar.gz
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
@ -15,8 +15,10 @@ scrcpy --new-display=/240 # use the main display size and 240 dpi
|
|||||||
|
|
||||||
On some devices, a launcher is available in the virtual display.
|
On some devices, a launcher is available in the virtual display.
|
||||||
|
|
||||||
When no launcher is available, the virtual display is empty. In that case, you
|
When no launcher is available (or if is explicitly disabled by
|
||||||
must [start an Android app](device.md#start-android-app).
|
[`--no-vd-system-decorations`](#system-decorations)), the virtual display is
|
||||||
|
empty. In that case, you must [start an Android
|
||||||
|
app](device.md#start-android-app).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@ -24,12 +26,27 @@ For example:
|
|||||||
scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
|
scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The app may itself be a launcher. For example, to run the open source [Fossify
|
||||||
|
Launcher]:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scrcpy --new-display=1920x1080 --no-vd-system-decorations --start-app=org.fossify.home
|
||||||
|
```
|
||||||
|
|
||||||
|
[Fossify Launcher]: https://f-droid.org/en/packages/org.fossify.home/
|
||||||
|
|
||||||
|
|
||||||
## System decorations
|
## System decorations
|
||||||
|
|
||||||
By default, virtual display system decorations are enabled. But some devices
|
By default, virtual display system decorations are enabled. To disable them, use
|
||||||
might display a broken UI;
|
`--no-vd-system-decorations`:
|
||||||
|
|
||||||
Use `--no-vd-system-decorations` to disable it.
|
```
|
||||||
|
scrcpy --new-display --no-vd-system-decorations
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful for some devices which might display a broken UI, or to disable
|
||||||
|
any default launcher UI available in virtual displays.
|
||||||
|
|
||||||
Note that if no app is started, no content will be rendered, so no video frame
|
Note that if no app is started, no content will be rendered, so no video frame
|
||||||
will be produced at all.
|
will be produced at all.
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
Download the [latest release]:
|
Download the [latest release]:
|
||||||
|
|
||||||
- [`scrcpy-win64-v3.0.zip`][direct-win64] (64-bit)
|
- [`scrcpy-win64-v3.0.2.zip`][direct-win64] (64-bit)
|
||||||
<sub>SHA-256: `dfbe8a8fef6535197acc506936bfd59d0aa0427e9b44fb2e5c550eae642f72be`</sub>
|
<sub>SHA-256: `f0de59f5d46127c87cd822d39d6665e016b86db4cd048101b262f6adb6766832`</sub>
|
||||||
- [`scrcpy-win32-v3.0.zip`][direct-win32] (32-bit)
|
- [`scrcpy-win32-v3.0.2.zip`][direct-win32] (32-bit)
|
||||||
<sub>SHA-256: `7cbf8d7a6ebfdca7b3b161e29a481c11088305f3e0a89d28e8e62f70c7bd0028`</sub>
|
<sub>SHA-256: `8db8d4984d642012c55802de71f507f8ff9f68a8cfed456d7a1982d47e065f64`</sub>
|
||||||
|
|
||||||
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest
|
||||||
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-win64-v3.0.zip
|
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-win64-v3.0.2.zip
|
||||||
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-win32-v3.0.zip
|
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-win32-v3.0.2.zip
|
||||||
|
|
||||||
and extract it.
|
and extract it.
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
BUILDDIR=build-auto
|
BUILDDIR=build-auto
|
||||||
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.0/scrcpy-server-v3.0
|
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v3.0.2/scrcpy-server-v3.0.2
|
||||||
PREBUILT_SERVER_SHA256=800044c62a94d5fc16f5ab9c86d45b1050eae3eb436514d1b0d2fe2646b894ea
|
PREBUILT_SERVER_SHA256=e19fe024bfa3367809494407ad6ca809a6f6e77dac95e99f85ba75144e0ba35d
|
||||||
|
|
||||||
echo "[scrcpy] Downloading prebuilt server..."
|
echo "[scrcpy] Downloading prebuilt server..."
|
||||||
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
wget "$PREBUILT_SERVER_URL" -O scrcpy-server
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
project('scrcpy', 'c',
|
project('scrcpy', 'c',
|
||||||
version: '3.0',
|
version: '3.0.2',
|
||||||
meson_version: '>= 0.48',
|
meson_version: '>= 0.48',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
@ -4,7 +4,14 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
|||||||
. build_common
|
. build_common
|
||||||
cd .. # root project dir
|
cd .. # root project dir
|
||||||
|
|
||||||
LINUX_BUILD_DIR="$WORK_DIR/build-linux"
|
if [[ $# != 1 ]]
|
||||||
|
then
|
||||||
|
echo "Syntax: $0 <arch>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARCH="$1"
|
||||||
|
LINUX_BUILD_DIR="$WORK_DIR/build-linux-$ARCH"
|
||||||
|
|
||||||
app/deps/adb_linux.sh
|
app/deps/adb_linux.sh
|
||||||
app/deps/sdl.sh linux native static
|
app/deps/sdl.sh linux native static
|
||||||
@ -29,8 +36,7 @@ ninja -C "$LINUX_BUILD_DIR"
|
|||||||
|
|
||||||
# Group intermediate outputs into a 'dist' directory
|
# Group intermediate outputs into a 'dist' directory
|
||||||
mkdir -p "$LINUX_BUILD_DIR/dist"
|
mkdir -p "$LINUX_BUILD_DIR/dist"
|
||||||
cp "$LINUX_BUILD_DIR"/app/scrcpy "$LINUX_BUILD_DIR/dist/scrcpy_bin"
|
cp "$LINUX_BUILD_DIR"/app/scrcpy "$LINUX_BUILD_DIR/dist/"
|
||||||
cp app/data/icon.png "$LINUX_BUILD_DIR/dist/"
|
cp app/data/icon.png "$LINUX_BUILD_DIR/dist/"
|
||||||
cp app/data/scrcpy_static_wrapper.sh "$LINUX_BUILD_DIR/dist/scrcpy"
|
|
||||||
cp app/scrcpy.1 "$LINUX_BUILD_DIR/dist/"
|
cp app/scrcpy.1 "$LINUX_BUILD_DIR/dist/"
|
||||||
cp -r "$ADB_INSTALL_DIR"/. "$LINUX_BUILD_DIR/dist/"
|
cp -r "$ADB_INSTALL_DIR"/. "$LINUX_BUILD_DIR/dist/"
|
||||||
|
@ -4,7 +4,14 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
|||||||
. build_common
|
. build_common
|
||||||
cd .. # root project dir
|
cd .. # root project dir
|
||||||
|
|
||||||
MACOS_BUILD_DIR="$WORK_DIR/build-macos"
|
if [[ $# != 1 ]]
|
||||||
|
then
|
||||||
|
echo "Syntax: $0 <arch>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARCH="$1"
|
||||||
|
MACOS_BUILD_DIR="$WORK_DIR/build-macos-$ARCH"
|
||||||
|
|
||||||
app/deps/adb_macos.sh
|
app/deps/adb_macos.sh
|
||||||
app/deps/sdl.sh macos native static
|
app/deps/sdl.sh macos native static
|
||||||
@ -29,8 +36,7 @@ ninja -C "$MACOS_BUILD_DIR"
|
|||||||
|
|
||||||
# Group intermediate outputs into a 'dist' directory
|
# Group intermediate outputs into a 'dist' directory
|
||||||
mkdir -p "$MACOS_BUILD_DIR/dist"
|
mkdir -p "$MACOS_BUILD_DIR/dist"
|
||||||
cp "$MACOS_BUILD_DIR"/app/scrcpy "$MACOS_BUILD_DIR/dist/scrcpy_bin"
|
cp "$MACOS_BUILD_DIR"/app/scrcpy "$MACOS_BUILD_DIR/dist/"
|
||||||
cp app/data/icon.png "$MACOS_BUILD_DIR/dist/"
|
cp app/data/icon.png "$MACOS_BUILD_DIR/dist/"
|
||||||
cp app/data/scrcpy_static_wrapper.sh "$MACOS_BUILD_DIR/dist/scrcpy"
|
|
||||||
cp app/scrcpy.1 "$MACOS_BUILD_DIR/dist/"
|
cp app/scrcpy.1 "$MACOS_BUILD_DIR/dist/"
|
||||||
cp -r "$ADB_INSTALL_DIR"/. "$MACOS_BUILD_DIR/dist/"
|
cp -r "$ADB_INSTALL_DIR"/. "$MACOS_BUILD_DIR/dist/"
|
||||||
|
@ -5,9 +5,10 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
|||||||
|
|
||||||
cd "$OUTPUT_DIR"
|
cd "$OUTPUT_DIR"
|
||||||
sha256sum "scrcpy-server-$VERSION" \
|
sha256sum "scrcpy-server-$VERSION" \
|
||||||
"scrcpy-linux-$VERSION.tar.gz" \
|
"scrcpy-linux-x86_64-$VERSION.tar.gz" \
|
||||||
"scrcpy-win32-$VERSION.zip" \
|
"scrcpy-win32-$VERSION.zip" \
|
||||||
"scrcpy-win64-$VERSION.zip" \
|
"scrcpy-win64-$VERSION.zip" \
|
||||||
"scrcpy-macos-$VERSION.tar.gz" \
|
"scrcpy-macos-aarch64-$VERSION.tar.gz" \
|
||||||
|
"scrcpy-macos-x86_64-$VERSION.tar.gz" \
|
||||||
| tee SHA256SUMS.txt
|
| tee SHA256SUMS.txt
|
||||||
echo "Release checksums generated in $PWD/SHA256SUMS.txt"
|
echo "Release checksums generated in $PWD/SHA256SUMS.txt"
|
||||||
|
@ -14,39 +14,39 @@ fi
|
|||||||
|
|
||||||
FORMAT=$2
|
FORMAT=$2
|
||||||
|
|
||||||
if [[ "$2" != zip && "$2" != tar.gz ]]
|
if [[ "$FORMAT" != zip && "$FORMAT" != tar.gz ]]
|
||||||
then
|
then
|
||||||
echo "Invalid format (expected zip or tar.gz): $2" >&2
|
echo "Invalid format (expected zip or tar.gz): $FORMAT" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BUILD_DIR="$WORK_DIR/build-$1"
|
BUILD_DIR="$WORK_DIR/build-$1"
|
||||||
ARCHIVE_DIR="$BUILD_DIR/release-archive"
|
ARCHIVE_DIR="$BUILD_DIR/release-archive"
|
||||||
TARGET="scrcpy-$1-$VERSION"
|
TARGET_DIRNAME="scrcpy-$1-$VERSION"
|
||||||
|
|
||||||
rm -rf "$ARCHIVE_DIR/$TARGET"
|
rm -rf "$ARCHIVE_DIR/$TARGET_DIRNAME"
|
||||||
mkdir -p "$ARCHIVE_DIR/$TARGET"
|
mkdir -p "$ARCHIVE_DIR/$TARGET_DIRNAME"
|
||||||
|
|
||||||
cp -r "$BUILD_DIR/dist/." "$ARCHIVE_DIR/$TARGET/"
|
cp -r "$BUILD_DIR/dist/." "$ARCHIVE_DIR/$TARGET_DIRNAME/"
|
||||||
cp "$WORK_DIR/build-server/server/scrcpy-server" "$ARCHIVE_DIR/$TARGET/"
|
cp "$WORK_DIR/build-server/server/scrcpy-server" "$ARCHIVE_DIR/$TARGET_DIRNAME/"
|
||||||
|
|
||||||
mkdir -p "$OUTPUT_DIR"
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
cd "$ARCHIVE_DIR"
|
cd "$ARCHIVE_DIR"
|
||||||
rm -f "$OUTPUT_DIR/$TARGET.$FORMAT"
|
rm -f "$OUTPUT_DIR/$TARGET_DIRNAME.$FORMAT"
|
||||||
|
|
||||||
case "$FORMAT" in
|
case "$FORMAT" in
|
||||||
zip)
|
zip)
|
||||||
zip -r "$OUTPUT_DIR/$TARGET.zip" "$TARGET"
|
zip -r "$OUTPUT_DIR/$TARGET_DIRNAME.zip" "$TARGET_DIRNAME"
|
||||||
;;
|
;;
|
||||||
tar.gz)
|
tar.gz)
|
||||||
tar cvf "$OUTPUT_DIR/$TARGET.tar.gz" "$TARGET"
|
tar cvzf "$OUTPUT_DIR/$TARGET_DIRNAME.tar.gz" "$TARGET_DIRNAME"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Invalid format (expected zip or tar.gz): $FORMAT" >&2
|
echo "Invalid format (expected zip or tar.gz): $FORMAT" >&2
|
||||||
exit 1
|
exit 1
|
||||||
esac
|
esac
|
||||||
|
|
||||||
rm -rf "$TARGET"
|
rm -rf "$TARGET_DIRNAME"
|
||||||
cd -
|
cd -
|
||||||
echo "Generated '$OUTPUT_DIR/$TARGET.$FORMAT'"
|
echo "Generated '$OUTPUT_DIR/$TARGET_DIRNAME.$FORMAT'"
|
||||||
|
@ -12,12 +12,12 @@ rm -rf output
|
|||||||
./build_server.sh
|
./build_server.sh
|
||||||
./build_windows.sh 32
|
./build_windows.sh 32
|
||||||
./build_windows.sh 64
|
./build_windows.sh 64
|
||||||
./build_linux.sh
|
./build_linux.sh x86_64
|
||||||
|
|
||||||
./package_server.sh
|
./package_server.sh
|
||||||
./package_client.sh win32 zip
|
./package_client.sh win32 zip
|
||||||
./package_client.sh win64 zip
|
./package_client.sh win64 zip
|
||||||
./package_client.sh linux tar.gz
|
./package_client.sh linux-x86_64 tar.gz
|
||||||
|
|
||||||
./generate_checksums.sh
|
./generate_checksums.sh
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.genymobile.scrcpy"
|
applicationId "com.genymobile.scrcpy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 35
|
targetSdkVersion 35
|
||||||
versionCode 30000
|
versionCode 30002
|
||||||
versionName "3.0"
|
versionName "3.0.2"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
SCRCPY_DEBUG=false
|
SCRCPY_DEBUG=false
|
||||||
SCRCPY_VERSION_NAME=3.0
|
SCRCPY_VERSION_NAME=3.0.2
|
||||||
|
|
||||||
PLATFORM=${ANDROID_PLATFORM:-35}
|
PLATFORM=${ANDROID_PLATFORM:-35}
|
||||||
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}
|
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-35.0.0}
|
||||||
|
@ -207,13 +207,15 @@ public final class CleanUp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayId != Device.DISPLAY_ID_NONE && Device.isScreenOn(displayId)) {
|
// Change the power of the main display when mirroring a virtual display
|
||||||
|
int targetDisplayId = displayId != Device.DISPLAY_ID_NONE ? displayId : 0;
|
||||||
|
if (Device.isScreenOn(targetDisplayId)) {
|
||||||
if (powerOffScreen) {
|
if (powerOffScreen) {
|
||||||
Ln.i("Power off screen");
|
Ln.i("Power off screen");
|
||||||
Device.powerOffScreen(displayId);
|
Device.powerOffScreen(targetDisplayId);
|
||||||
} else if (restoreDisplayPower) {
|
} else if (restoreDisplayPower) {
|
||||||
Ln.i("Restoring display power");
|
Ln.i("Restoring display power");
|
||||||
Device.setDisplayPower(displayId, true);
|
Device.setDisplayPower(targetDisplayId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import android.content.IOnPrimaryClipChangedListener;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.KeyCharacterMap;
|
import android.view.KeyCharacterMap;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@ -281,7 +282,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
setClipboard(msg.getText(), msg.getPaste(), msg.getSequence());
|
setClipboard(msg.getText(), msg.getPaste(), msg.getSequence());
|
||||||
break;
|
break;
|
||||||
case ControlMessage.TYPE_SET_DISPLAY_POWER:
|
case ControlMessage.TYPE_SET_DISPLAY_POWER:
|
||||||
if (supportsInputEvents && displayId != Device.DISPLAY_ID_NONE) {
|
if (supportsInputEvents) {
|
||||||
setDisplayPower(msg.getOn());
|
setDisplayPower(msg.getOn());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -350,24 +351,47 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
return successCount;
|
return successCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean injectTouch(int action, long pointerId, Position position, float pressure, int actionButton, int buttons) {
|
private Pair<Point, Integer> getEventPointAndDisplayId(Position position) {
|
||||||
long now = SystemClock.uptimeMillis();
|
|
||||||
|
|
||||||
// it hides the field on purpose, to read it with atomic access
|
// it hides the field on purpose, to read it with atomic access
|
||||||
@SuppressWarnings("checkstyle:HiddenField")
|
@SuppressWarnings("checkstyle:HiddenField")
|
||||||
DisplayData displayData = this.displayData.get();
|
DisplayData displayData = this.displayData.get();
|
||||||
assert displayData != null : "Cannot receive a touch event without a display";
|
// In scrcpy, displayData should never be null (a touch event can only be generated from the client when a video frame is present).
|
||||||
|
// However, it is possible to send events without video playback when using scrcpy-server alone (except for virtual displays).
|
||||||
|
assert displayData != null || displayId != Device.DISPLAY_ID_NONE : "Cannot receive a positional event without a display";
|
||||||
|
|
||||||
Point point = displayData.positionMapper.map(position);
|
Point point;
|
||||||
if (point == null) {
|
int targetDisplayId;
|
||||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
if (displayData != null) {
|
||||||
Size eventSize = position.getScreenSize();
|
point = displayData.positionMapper.map(position);
|
||||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
if (point == null) {
|
||||||
Ln.v("Ignore touch event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||||
|
Size eventSize = position.getScreenSize();
|
||||||
|
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||||
|
Ln.v("Ignore positional event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
targetDisplayId = displayData.virtualDisplayId;
|
||||||
|
} else {
|
||||||
|
// No display, use the raw coordinates
|
||||||
|
point = position.getPoint();
|
||||||
|
targetDisplayId = displayId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair.create(point, targetDisplayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean injectTouch(int action, long pointerId, Position position, float pressure, int actionButton, int buttons) {
|
||||||
|
long now = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
|
Pair<Point, Integer> pair = getEventPointAndDisplayId(position);
|
||||||
|
if (pair == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point point = pair.first;
|
||||||
|
int targetDisplayId = pair.second;
|
||||||
|
|
||||||
int pointerIndex = pointersState.getPointerIndex(pointerId);
|
int pointerIndex = pointersState.getPointerIndex(pointerId);
|
||||||
if (pointerIndex == -1) {
|
if (pointerIndex == -1) {
|
||||||
Ln.w("Too many pointers for touch event");
|
Ln.w("Too many pointers for touch event");
|
||||||
@ -421,7 +445,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
// First button pressed: ACTION_DOWN
|
// First button pressed: ACTION_DOWN
|
||||||
MotionEvent downEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_DOWN, pointerCount, pointerProperties,
|
MotionEvent downEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_DOWN, pointerCount, pointerProperties,
|
||||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||||
if (!Device.injectEvent(downEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
if (!Device.injectEvent(downEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,7 +456,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
if (!InputManager.setActionButton(pressEvent, actionButton)) {
|
if (!InputManager.setActionButton(pressEvent, actionButton)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Device.injectEvent(pressEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
if (!Device.injectEvent(pressEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +470,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
if (!InputManager.setActionButton(releaseEvent, actionButton)) {
|
if (!InputManager.setActionButton(releaseEvent, actionButton)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Device.injectEvent(releaseEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
if (!Device.injectEvent(releaseEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +478,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
// Last button released: ACTION_UP
|
// Last button released: ACTION_UP
|
||||||
MotionEvent upEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_UP, pointerCount, pointerProperties,
|
MotionEvent upEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_UP, pointerCount, pointerProperties,
|
||||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||||
if (!Device.injectEvent(upEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
if (!Device.injectEvent(upEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,27 +489,20 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
|
|
||||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||||
DEFAULT_DEVICE_ID, 0, source, 0);
|
DEFAULT_DEVICE_ID, 0, source, 0);
|
||||||
return Device.injectEvent(event, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC);
|
return Device.injectEvent(event, targetDisplayId, Device.INJECT_MODE_ASYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) {
|
private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) {
|
||||||
long now = SystemClock.uptimeMillis();
|
long now = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
// it hides the field on purpose, to read it with atomic access
|
Pair<Point, Integer> pair = getEventPointAndDisplayId(position);
|
||||||
@SuppressWarnings("checkstyle:HiddenField")
|
if (pair == null) {
|
||||||
DisplayData displayData = this.displayData.get();
|
|
||||||
assert displayData != null : "Cannot receive a scroll event without a display";
|
|
||||||
|
|
||||||
Point point = displayData.positionMapper.map(position);
|
|
||||||
if (point == null) {
|
|
||||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
|
||||||
Size eventSize = position.getScreenSize();
|
|
||||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
|
||||||
Ln.v("Ignore scroll event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point point = pair.first;
|
||||||
|
int targetDisplayId = pair.second;
|
||||||
|
|
||||||
MotionEvent.PointerProperties props = pointerProperties[0];
|
MotionEvent.PointerProperties props = pointerProperties[0];
|
||||||
props.id = 0;
|
props.id = 0;
|
||||||
|
|
||||||
@ -497,7 +514,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
|
|
||||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||||
DEFAULT_DEVICE_ID, 0, InputDevice.SOURCE_MOUSE, 0);
|
DEFAULT_DEVICE_ID, 0, InputDevice.SOURCE_MOUSE, 0);
|
||||||
return Device.injectEvent(event, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC);
|
return Device.injectEvent(event, targetDisplayId, Device.INJECT_MODE_ASYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -691,9 +708,12 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setDisplayPower(boolean on) {
|
private void setDisplayPower(boolean on) {
|
||||||
boolean setDisplayPowerOk = Device.setDisplayPower(displayId, on);
|
// Change the power of the main display when mirroring a virtual display
|
||||||
|
int targetDisplayId = displayId != Device.DISPLAY_ID_NONE ? displayId : 0;
|
||||||
|
boolean setDisplayPowerOk = Device.setDisplayPower(targetDisplayId, on);
|
||||||
if (setDisplayPowerOk) {
|
if (setDisplayPowerOk) {
|
||||||
keepDisplayPowerOff = !on;
|
// Do not keep display power off for virtual displays: MOD+p must wake up the physical device
|
||||||
|
keepDisplayPowerOff = displayId != Device.DISPLAY_ID_NONE && !on;
|
||||||
Ln.i("Device display turned " + (on ? "on" : "off"));
|
Ln.i("Device display turned " + (on ? "on" : "off"));
|
||||||
if (cleanUp != null) {
|
if (cleanUp != null) {
|
||||||
boolean mustRestoreOnExit = !on;
|
boolean mustRestoreOnExit = !on;
|
||||||
|
@ -40,6 +40,10 @@ public final class Device {
|
|||||||
public static final int INJECT_MODE_WAIT_FOR_RESULT = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT;
|
public static final int INJECT_MODE_WAIT_FOR_RESULT = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT;
|
||||||
public static final int INJECT_MODE_WAIT_FOR_FINISH = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH;
|
public static final int INJECT_MODE_WAIT_FOR_FINISH = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH;
|
||||||
|
|
||||||
|
// The new display power method introduced in Android 15 does not work as expected:
|
||||||
|
// <https://github.com/Genymobile/scrcpy/issues/5530>
|
||||||
|
private static final boolean USE_ANDROID_15_DISPLAY_POWER = false;
|
||||||
|
|
||||||
private Device() {
|
private Device() {
|
||||||
// not instantiable
|
// not instantiable
|
||||||
}
|
}
|
||||||
@ -127,7 +131,7 @@ public final class Device {
|
|||||||
public static boolean setDisplayPower(int displayId, boolean on) {
|
public static boolean setDisplayPower(int displayId, boolean on) {
|
||||||
assert displayId != Device.DISPLAY_ID_NONE;
|
assert displayId != Device.DISPLAY_ID_NONE;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= AndroidVersions.API_35_ANDROID_15) {
|
if (USE_ANDROID_15_DISPLAY_POWER && Build.VERSION.SDK_INT >= AndroidVersions.API_35_ANDROID_15) {
|
||||||
return ServiceManager.getDisplayManager().requestDisplayPower(displayId, on);
|
return ServiceManager.getDisplayManager().requestDisplayPower(displayId, on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,4 +72,8 @@ public final class IO {
|
|||||||
Throwable cause = e.getCause();
|
Throwable cause = e.getCause();
|
||||||
return cause instanceof ErrnoException && ((ErrnoException) cause).errno == OsConstants.EPIPE;
|
return cause instanceof ErrnoException && ((ErrnoException) cause).errno == OsConstants.EPIPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isBrokenPipe(Exception e) {
|
||||||
|
return e instanceof IOException && isBrokenPipe((IOException) e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,8 +112,12 @@ public class SurfaceEncoder implements AsyncProcessor {
|
|||||||
// The capture might have been closed internally (for example if the camera is disconnected)
|
// The capture might have been closed internally (for example if the camera is disconnected)
|
||||||
alive = !stopped.get() && !capture.isClosed();
|
alive = !stopped.get() && !capture.isClosed();
|
||||||
}
|
}
|
||||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
} catch (IllegalStateException | IllegalArgumentException | IOException e) {
|
||||||
Ln.e("Encoding error: " + e.getClass().getName() + ": " + e.getMessage());
|
if (IO.isBrokenPipe(e)) {
|
||||||
|
// Do not retry on broken pipe, which is expected on close because the socket is closed by the client
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
Ln.e("Capture/encoding error: " + e.getClass().getName() + ": " + e.getMessage());
|
||||||
if (!prepareRetry(size)) {
|
if (!prepareRetry(size)) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,9 @@ public final class DisplayManager {
|
|||||||
if ("onDisplayChanged".equals(method.getName())) {
|
if ("onDisplayChanged".equals(method.getName())) {
|
||||||
listener.onDisplayChanged((int) args[0]);
|
listener.onDisplayChanged((int) args[0]);
|
||||||
}
|
}
|
||||||
|
if ("toString".equals(method.getName())) {
|
||||||
|
return "DisplayListener";
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user