diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index 56258e4e0..000000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: "gitsubmodule"
- directory: "/"
- target-branch: "master"
- schedule:
- interval: "daily"
- commit-message:
- prefix: "Git submodule"
- labels:
- - "dependencies"
diff --git a/.github/patches/apply_flutter_3.44_source_patches.sh b/.github/patches/apply_flutter_3.44_source_patches.sh
index 3a7ab99dc..2b4bfcc0d 100644
--- a/.github/patches/apply_flutter_3.44_source_patches.sh
+++ b/.github/patches/apply_flutter_3.44_source_patches.sh
@@ -17,6 +17,109 @@
# therefore CRLF-safe.
set -euo pipefail
+readonly NO_MATCHES=0
+readonly SINGLE_MATCH=1
+readonly THEME_MATCHES=2
+
+has_exact_count() {
+ local -r expected_count="$1"
+ local -r pattern="$2"
+ local -r file="$3"
+ local actual_count
+ [[ -r "$file" ]] || return 1
+ actual_count="$(grep -cF "$pattern" "$file" || true)"
+ [[ "$actual_count" -eq "$expected_count" ]]
+}
+
+# The target background-color line must directly follow DialogThemeData in the selected range.
+has_dialog_background_in_theme_range() {
+ local -r start_pattern="$1"
+ local -r end_pattern="$2"
+ local -r target_pattern="$3"
+ local -r file="$4"
+ awk -v start_pattern="$start_pattern" \
+ -v end_pattern="$end_pattern" \
+ -v target_pattern="$target_pattern" '
+ index($0, start_pattern) {
+ in_theme = 1
+ next
+ }
+ in_theme && index($0, end_pattern) {
+ exit
+ }
+ in_theme && index($0, "dialogTheme: DialogThemeData(") {
+ if (getline > 0) {
+ line = $0
+ sub(/\r$/, "", line)
+ sub(/^[[:space:]]+/, "", line)
+ matched = line == target_pattern
+ }
+ exit
+ }
+ END {
+ exit matched ? 0 : 1
+ }
+ ' "$file"
+}
+
+validate_patch_inputs() {
+ if [[ ! -f flutter/lib/common.dart || ! -r flutter/lib/common.dart ]]; then
+ echo "Flutter 3.44 source patch input is missing or unreadable: flutter/lib/common.dart" >&2
+ return 1
+ fi
+ if [[ ! -f flutter/pubspec.yaml || ! -r flutter/pubspec.yaml ]]; then
+ echo "Flutter 3.44 source patch input is missing or unreadable: flutter/pubspec.yaml" >&2
+ return 1
+ fi
+}
+
+is_complete_patch_state() {
+ has_exact_count "$THEME_MATCHES" 'dialogTheme: DialogThemeData(' flutter/lib/common.dart &&
+ has_exact_count "$THEME_MATCHES" 'tabBarTheme: const TabBarThemeData(' flutter/lib/common.dart &&
+ has_exact_count "$SINGLE_MATCH" 'backgroundColor: Colors.white,' flutter/lib/common.dart &&
+ has_exact_count "$SINGLE_MATCH" 'backgroundColor: Color(0xFF18191E),' flutter/lib/common.dart &&
+ has_exact_count "$SINGLE_MATCH" 'extended_text: 15.0.2' flutter/pubspec.yaml &&
+ has_exact_count "$SINGLE_MATCH" 'google_fonts: ^8.1.0' flutter/pubspec.yaml &&
+ has_exact_count "$NO_MATCHES" 'dialogTheme: DialogTheme(' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'tabBarTheme: const TabBarTheme(' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'extended_text: 14.0.0' flutter/pubspec.yaml &&
+ has_exact_count "$NO_MATCHES" 'google_fonts: ^6.2.1' flutter/pubspec.yaml &&
+ has_dialog_background_in_theme_range 'static ThemeData lightTheme = ThemeData(' \
+ 'static ThemeData darkTheme = ThemeData(' 'backgroundColor: Colors.white,' \
+ flutter/lib/common.dart &&
+ has_dialog_background_in_theme_range 'static ThemeData darkTheme = ThemeData(' \
+ 'scrollbarTheme: scrollbarThemeDark,' 'backgroundColor: Color(0xFF18191E),' \
+ flutter/lib/common.dart
+}
+
+is_unpatched_state() {
+ has_exact_count "$THEME_MATCHES" 'dialogTheme: DialogTheme(' flutter/lib/common.dart &&
+ has_exact_count "$THEME_MATCHES" 'tabBarTheme: const TabBarTheme(' flutter/lib/common.dart &&
+ has_exact_count "$SINGLE_MATCH" 'extended_text: 14.0.0' flutter/pubspec.yaml &&
+ has_exact_count "$SINGLE_MATCH" 'google_fonts: ^6.2.1' flutter/pubspec.yaml &&
+ has_exact_count "$NO_MATCHES" 'dialogTheme: DialogThemeData(' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'tabBarTheme: const TabBarThemeData(' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'backgroundColor: Colors.white,' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'backgroundColor: Color(0xFF18191E),' flutter/lib/common.dart &&
+ has_exact_count "$NO_MATCHES" 'extended_text: 15.0.2' flutter/pubspec.yaml &&
+ has_exact_count "$NO_MATCHES" 'google_fonts: ^8.1.0' flutter/pubspec.yaml
+}
+
+if ! validate_patch_inputs; then
+ exit 1
+fi
+
+if is_complete_patch_state; then
+ echo "Flutter 3.44 source patches already applied."
+ git --no-pager diff -- flutter/lib/common.dart flutter/pubspec.yaml
+ exit 0
+fi
+
+if ! is_unpatched_state; then
+ echo "Flutter 3.44 source patches are partially applied or their anchors have drifted." >&2
+ exit 1
+fi
+
# ThemeData API renames (Flutter 3.27+):
sed -i 's/dialogTheme: DialogTheme(/dialogTheme: DialogThemeData(/g' flutter/lib/common.dart
sed -i 's/tabBarTheme: const TabBarTheme(/tabBarTheme: const TabBarThemeData(/g' flutter/lib/common.dart
@@ -28,12 +131,10 @@ sed -i '/static ThemeData darkTheme = ThemeData(/,/scrollbarTheme: scrollbarThem
sed -i 's/extended_text: 14.0.0/extended_text: 15.0.2/' flutter/pubspec.yaml
sed -i 's/google_fonts: \^6.2.1/google_fonts: ^8.1.0/' flutter/pubspec.yaml
-# Fail loudly if any expected string drifted, so we never silently build unpatched:
-grep -qF 'dialogTheme: DialogThemeData(' flutter/lib/common.dart
-grep -qF 'tabBarTheme: const TabBarThemeData(' flutter/lib/common.dart
-grep -qF 'backgroundColor: Colors.white,' flutter/lib/common.dart
-grep -qF 'backgroundColor: Color(0xFF18191E),' flutter/lib/common.dart
-grep -qF 'extended_text: 15.0.2' flutter/pubspec.yaml
-grep -qF 'google_fonts: ^8.1.0' flutter/pubspec.yaml
+# Fail loudly if any expected substitution did not produce the complete state.
+if ! is_complete_patch_state; then
+ echo "Flutter 3.44 source patches did not produce the expected state." >&2
+ exit 1
+fi
git --no-pager diff -- flutter/lib/common.dart flutter/pubspec.yaml
diff --git a/.github/patches/apply_flutter_3.44_web_patches.sh b/.github/patches/apply_flutter_3.44_web_patches.sh
new file mode 100755
index 000000000..24ce7f1b4
--- /dev/null
+++ b/.github/patches/apply_flutter_3.44_web_patches.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# Prepares a web build on Flutter 3.44.x. Companion to
+# apply_flutter_3.44_source_patches.sh (which it runs first): the web target
+# additionally needs qr_code_scanner's web implementation patched for the
+# dart:ui platformViewRegistry removal, and flutter/web/fonts refreshed with
+# the font paths the 3.44 engine requests for offline/air-gapped support
+# (rustdesk-server-pro#996; see flutter/web/fonts/sync_fonts.py).
+#
+# Run from the repository root with Flutter 3.44.x on PATH, then build:
+# bash .github/patches/apply_flutter_3.44_web_patches.sh
+# (cd flutter && flutter build web --release) # or ./web/js/flutter_build.py
+#
+# Idempotent. To undo the source changes locally:
+# git checkout -- flutter/lib/common.dart flutter/pubspec.yaml flutter/pubspec.lock
+set -euo pipefail
+
+flutter --version | grep -q "Flutter 3\.44\." || {
+ echo "Flutter 3.44.x must be on PATH; found:" >&2
+ flutter --version | grep "^Flutter" >&2 || true
+ exit 1
+}
+
+# Shared 3.44 source/pubspec patches own their complete-state validation.
+bash .github/patches/apply_flutter_3.44_source_patches.sh
+
+# Populate the pub cache with the 3.44 dependency resolution.
+(cd flutter && flutter pub get)
+
+# qr_code_scanner 1.0.1 (unmaintained) reads platformViewRegistry from
+# dart:ui, which Flutter 3.44 removed; point it at dart:ui_web instead. The
+# patched file also compiles on Flutter 3.24 (dart:ui_web exists there), so
+# mutating the shared pub cache is safe for other local builds.
+QR_WEB="${PUB_CACHE:-$HOME/.pub-cache}/hosted/pub.dev/qr_code_scanner-1.0.1/lib/src/web/flutter_qr_web.dart"
+if ! grep -qF "dart:ui_web" "$QR_WEB"; then
+ sed -i.bak "s|import 'dart:ui' as ui;|import 'dart:ui' as ui; import 'dart:ui_web' as ui_web;|" "$QR_WEB"
+ rm -f "$QR_WEB.bak"
+fi
+if grep -qF "ui.platformViewRegistry" "$QR_WEB"; then
+ sed -i.bak "s|ui\.platformViewRegistry|ui_web.platformViewRegistry|g" "$QR_WEB"
+ rm -f "$QR_WEB.bak"
+fi
+
+# Mirror the fonts this engine version requests into flutter/web/fonts.
+python3 flutter/web/fonts/sync_fonts.py
+
+# Fail loudly if any expected state is missing:
+grep -qF "import 'dart:ui' as ui; import 'dart:ui_web' as ui_web;" "$QR_WEB"
+grep -qF "ui_web.platformViewRegistry" "$QR_WEB"
+grep -qF 'google_fonts: ^8.1.0' flutter/pubspec.yaml
+
+echo "Flutter 3.44 web patches applied."
diff --git a/.github/workflows/bridge.yml b/.github/workflows/bridge.yml
index a7b74fa55..9d31399c8 100644
--- a/.github/workflows/bridge.yml
+++ b/.github/workflows/bridge.yml
@@ -30,7 +30,7 @@ jobs:
target: x86_64-unknown-linux-gnu,
os: ubuntu-22.04,
extra-build-args: "",
- flutter-version: "3.44.0",
+ flutter-version: "3.44.8",
artifact-name: "bridge-artifact-flutter-3.44",
}
steps:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 173eda9f4..ecc9ee782 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,7 +5,7 @@ env:
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
# for multiarch gcc compatibility
- VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
+ VCPKG_COMMIT_ID: "9e593bb18ea69cc5095e012465dcd675a822ed0d"
on:
workflow_dispatch:
@@ -124,7 +124,6 @@ jobs:
gcc \
git \
g++ \
- libpam0g-dev \
libasound2-dev \
libunwind-dev \
libgstreamer1.0-dev \
diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml
index 464b1ebdf..bf1b7610c 100644
--- a/.github/workflows/flutter-build.yml
+++ b/.github/workflows/flutter-build.yml
@@ -31,20 +31,20 @@ env:
# engine is 3.44. Every other platform stays on FLUTTER_VERSION (3.24.5) until Windows 7
# support is restored after the upstream-wide Flutter bump. The arm64 job patches the few
# 3.44-only source/pubspec changes on the fly (see "Patch RustDesk sources for Flutter 3.44").
- FLUTTER_WINDOWS_ARM_VERSION: "3.44.0"
+ FLUTTER_WINDOWS_ARM_VERSION: "3.44.9"
# for arm64 linux because official Dart SDK does not work
FLUTTER_ELINUX_VERSION: "3.16.9"
TAG_NAME: "${{ inputs.upload-tag }}"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
- # vcpkg version: 2025.08.27
+ # vcpkg version: 2026.07.29
# If we change the `VCPKG COMMIT_ID`, please remember:
# 1. Call `$VCPKG_ROOT/vcpkg x-update-baseline` to update the baseline in `vcpkg.json`.
# Or we may face build issue like
# https://github.com/rustdesk/rustdesk/actions/runs/14414119794/job/40427970174
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
- VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
+ VCPKG_COMMIT_ID: "9e593bb18ea69cc5095e012465dcd675a822ed0d"
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
- VERSION: "1.4.9"
+ VERSION: "1.5.0"
NDK_VERSION: "r28c"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
@@ -224,7 +224,9 @@ jobs:
run: |
cp .github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff $(dirname $(dirname $(which flutter)))
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]]; then
+ git apply flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
- name: Patch RustDesk sources for Flutter 3.44 (arm64)
# arm64 is the only target on Flutter 3.44; apply its source/pubspec deltas on the fly
@@ -643,7 +645,9 @@ jobs:
- name: Patch flutter
run: |
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]]; then
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
- name: Setup vcpkg with Github Actions binary cache
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
@@ -822,7 +826,9 @@ jobs:
- name: Patch flutter
run: |
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]]; then
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
- name: Workaround for flutter issue
shell: bash
@@ -1069,7 +1075,6 @@ jobs:
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
- libpam0g-dev \
libpulse-dev \
libva-dev \
libxcb-randr0-dev \
@@ -1099,7 +1104,9 @@ jobs:
- name: Patch flutter
run: |
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]]; then
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
id: setup-ndk
@@ -1341,7 +1348,6 @@ jobs:
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
- libpam0g-dev \
libpulse-dev \
libva-dev \
libxcb-randr0-dev \
@@ -1371,7 +1377,9 @@ jobs:
- name: Patch flutter
run: |
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]]; then
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
- name: Restore bridge files
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
@@ -1630,7 +1638,6 @@ jobs:
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
- libpam0g-dev \
libpulse-dev \
libva-dev \
libxcb-randr0-dev \
@@ -1815,6 +1822,275 @@ jobs:
files: |
res/rustdesk-${{ env.VERSION }}*.zst
+ # Same build as build-rustdesk-linux x86_64 -- same vcpkg/ffmpeg, same ubuntu18.04 container, same
+ # rust and flutter -- only with the drm feature on, so it ships as the separate
+ # rustdesk-unattended-wayland deb. libdrmtap is built on the runner because bionic's meson is too
+ # old for it. A separate job rather than a matrix entry of build-rustdesk-linux: appimage and
+ # flatpak need that job, and a failure here must not skip them.
+ build-rustdesk-linux-drm:
+ needs: [generate-bridge]
+ name: build rustdesk linux drm x86_64
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Export GitHub Actions cache environment variables
+ uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
+ with:
+ script: |
+ core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
+ core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
+
+ - name: Maximize build space
+ run: |
+ sudo rm -rf /opt/ghc
+ sudo rm -rf /usr/local/lib/android
+ sudo rm -rf /usr/share/dotnet
+ sudo apt-get update -y
+ sudo apt-get install -y nasm
+ sudo apt-get install -y qemu-user-static
+
+ - name: Checkout source code
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ submodules: recursive
+
+ - name: Set Swap Space
+ uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0
+ with:
+ swap-size-gb: 12
+
+ - name: Free Space
+ run: |
+ df -h
+ free -m
+
+ - name: Install Rust toolchain
+ uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
+ with:
+ toolchain: ${{ env.RUST_VERSION }}
+ targets: x86_64-unknown-linux-gnu
+ components: "rustfmt"
+
+ - name: Save Rust toolchain version
+ run: |
+ RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
+ echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV
+
+ - name: Disable rust bridge build
+ run: |
+ # only build cdylib
+ sed -i "s/\[\"cdylib\", \"staticlib\", \"rlib\"\]/\[\"cdylib\"\]/g" Cargo.toml
+
+ - name: Restore bridge files
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: bridge-artifact
+ path: ./
+
+ - name: Setup vcpkg with Github Actions binary cache
+ uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
+ with:
+ vcpkgDirectory: /opt/artifacts/vcpkg
+ vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
+ doNotCache: false
+
+ - name: Install vcpkg dependencies
+ run: |
+ sudo apt install -y libva-dev && apt show libva-dev
+ if ! $VCPKG_ROOT/vcpkg \
+ install \
+ --triplet x64-linux \
+ --x-install-root="$VCPKG_ROOT/installed"; then
+ find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
+ echo "$_1:"
+ echo "======"
+ cat "$_1"
+ echo "======"
+ echo ""
+ done
+ exit 1
+ fi
+ head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-x64-linux-rel-out.log" || true
+ shell: bash
+
+ # The container's meson is too old to build libdrmtap, so build it here from the pin in
+ # build.py and hand the .so to the container below via DRMTAP_PREBUILT_DIR.
+ - name: Build libdrmtap
+ run: |
+ sudo apt-get install -y meson ninja-build pkg-config \
+ libdrm-dev libegl1-mesa-dev libgles2-mesa-dev
+ python3 - <<'PY'
+ import importlib.util, sys
+ spec = importlib.util.spec_from_file_location("b", "build.py")
+ b = importlib.util.module_from_spec(spec)
+ sys.argv = ["build.py"]
+ spec.loader.exec_module(b)
+ print(f"::notice::built {b.build_libdrmtap_so()}")
+ PY
+ shell: bash
+
+ - uses: rustdesk-org/run-on-arch-action@d3fcfbb632b84cf7f6bc772bfaaa2c2f4f8789a8 # no release tag; commit 2026-05-26
+ name: Build rustdesk
+ id: vcpkg
+ with:
+ arch: x86_64
+ distro: ubuntu18.04
+ githubToken: ${{ github.token }}
+ setup: |
+ ls -l "${PWD}"
+ ls -l /opt/artifacts/vcpkg/installed
+ dockerRunArgs: |
+ --volume "${PWD}:/workspace"
+ --volume "/opt/artifacts:/opt/artifacts"
+ shell: /bin/bash
+ install: |
+ apt-get update -y
+ echo -e "installing deps"
+ apt-get install -y \
+ build-essential \
+ clang \
+ cmake \
+ curl \
+ gcc \
+ git \
+ g++ \
+ libayatana-appindicator3-dev \
+ libasound2-dev \
+ libclang-10-dev \
+ libgstreamer1.0-dev \
+ libgstreamer-plugins-base1.0-dev \
+ libgtk-3-dev \
+ libpulse-dev \
+ libva-dev \
+ libxcb-randr0-dev \
+ libxcb-shape0-dev \
+ libxcb-xfixes0-dev \
+ libxdo-dev \
+ libxfixes-dev \
+ llvm-10-dev \
+ nasm \
+ ninja-build \
+ pkg-config \
+ tree \
+ python3 \
+ rpm \
+ unzip \
+ wget \
+ xz-utils \
+ libssl-dev
+ # we have libopus compiled by us.
+ apt-get remove -y libopus-dev || true
+ # output devs
+ ls -l ./
+ tree -L 3 /opt/artifacts/vcpkg/installed
+ run: |
+ # disable git safe.directory
+ git config --global --add safe.directory "*"
+ # rust
+ pushd /opt
+ # do not use rustup, because memory overflow in qemu
+ wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-x86_64-unknown-linux-gnu.tar.gz
+ tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
+ cd rust-${{env.RUST_TOOLCHAIN_VERSION}}-x86_64-unknown-linux-gnu && ./install.sh
+ rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-x86_64-unknown-linux-gnu
+ # edit config
+ mkdir -p ~/.cargo/
+ echo """
+ [source.crates-io]
+ registry = 'https://github.com/rust-lang/crates.io-index'
+ """ > ~/.cargo/config
+ cat ~/.cargo/config
+ # start build
+ pushd /workspace
+ export VCPKG_ROOT=/opt/artifacts/vcpkg
+ # use the .so built on the runner; build.py checks it is the pinned checkout
+ export DRMTAP_PREBUILT_DIR=/workspace/third_party/libdrmtap/build-pkg
+ # ask build.py for the features so this line and the packaging line cannot drift
+ FEATURES=$(python3 ./build.py --flutter --drm --hwcodec --unix-file-copy-paste --print-features)
+ # an empty or error-shaped value would silently build a stock binary
+ for want in drm drm-wake; do
+ case ",$FEATURES," in
+ *",$want,"*) ;;
+ *) echo "::error::build.py returned no '$want' feature: $FEATURES"; exit 1 ;;
+ esac
+ done
+ cargo build --locked --lib --features "$FEATURES" --release
+ rm -rf target/release/deps target/release/build
+ rm -rf ~/.cargo
+
+ # Setup Flutter
+ # disable git safe.directory
+ git config --global --add safe.directory "*"
+ export PATH=/opt/flutter/bin:$PATH
+ pushd /opt
+ wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz
+ tar xf flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz
+ flutter doctor -v
+
+ if [[ "3.24.5" == ${{ env.FLUTTER_VERSION }} ]]; then
+ pushd /opt/flutter
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ popd
+ fi
+
+ # build flutter
+ pushd /workspace
+ export CARGO_INCREMENTAL=0
+ export DEB_ARCH=amd64
+ python3 ./build.py --flutter --drm --hwcodec --unix-file-copy-paste --skip-cargo
+ for name in rustdesk*??.deb; do
+ mv "$name" "${name%%.deb}-x86_64.deb"
+ done
+
+ # build.py can exit 0 on some inner failures, so check the artifact rather than the status.
+ # The package name is the informed consent for consent-free capture, so a stock binary must
+ # never ship under it: assert the bundled library AND the dlopen path in the binary.
+ - name: Check the deb is a drm build
+ run: |
+ set -euo pipefail
+ # Resolve by glob, not from env.VERSION: build.py names the deb from Cargo.toml, so a
+ # hardcoded name fails with a bare exit 1 the first time those two drift.
+ shopt -s nullglob
+ debs=(rustdesk-unattended-wayland-*-x86_64.deb)
+ if [ "${#debs[@]}" -ne 1 ]; then
+ echo "::error::expected one rustdesk-unattended-wayland-*-x86_64.deb, found ${#debs[@]}: ${debs[*]-none}"
+ exit 1
+ fi
+ deb="${debs[0]}"
+ echo "DRM_DEB=$deb" >> "$GITHUB_ENV"
+ contents="$(dpkg -c "$deb")"
+ if [[ ! "$contents" =~ usr/lib/rustdesk/libdrmtap\.so\.0\.[0-9]+\.[0-9]+ ]]; then
+ echo "::error::$deb has no versioned libdrmtap.so.0.x.y"
+ exit 1
+ fi
+ if [[ "$contents" != *"usr/lib/rustdesk/libdrmtap.so.0 ->"* ]]; then
+ echo "::error::$deb has no libdrmtap.so.0 soname symlink"
+ exit 1
+ fi
+ rm -rf /tmp/deb && dpkg-deb -R "$deb" /tmp/deb
+ if ! grep -qF /usr/lib/rustdesk/libdrmtap.so.0 /tmp/deb/usr/share/rustdesk/lib/librustdesk.so; then
+ echo "::error::$deb was not built with the drm feature"
+ exit 1
+ fi
+ shell: bash
+
+ - name: Publish debian package
+ if: env.UPLOAD_ARTIFACT == 'true'
+ uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
+ with:
+ prerelease: true
+ tag_name: ${{ env.TAG_NAME }}
+ files: |
+ ${{ env.DRM_DEB }}
+
+ # No UPLOAD_ARTIFACT gate: on a PR this is the only way to get at the deb that was just built.
+ # always(), because a deb that failed the check above is the one most worth downloading.
+ - name: Upload deb
+ if: always() && env.DRM_DEB != ''
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: ${{ env.DRM_DEB }}
+ path: ${{ env.DRM_DEB }}
+
build-rustdesk-linux-sciter:
if: ${{ inputs.upload-artifact }}
runs-on: ${{ matrix.job.on }}
@@ -1912,7 +2188,6 @@ jobs:
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
liblzma-dev \
- libpam0g-dev \
libpulse-dev \
libva-dev \
libxcb-randr0-dev \
@@ -1989,7 +2264,7 @@ jobs:
mkdir -p ~/.cargo/
echo """
[source.crates-io]
- registry = 'https://github.com/rust-lang/crates.io-index'
+ registry = 'sparse+https://index.crates.io/'
""" > ~/.cargo/config
cat ~/.cargo/config
# install dependencies from vcpkg
@@ -2209,7 +2484,18 @@ jobs:
shell: bash
run: |
cd $(dirname $(dirname $(which flutter)))
- [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ if [[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]]; then
+ git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
+ fi
+
+ - name: Patch sources for Flutter 3.44 web
+ # No-op while the web stays on Flutter 3.24.5; makes this job work as-is
+ # once FLUTTER_VERSION moves to 3.44.x (qr_code_scanner + fonts, see script).
+ shell: bash
+ run: |
+ if [[ "${{ env.FLUTTER_VERSION }}" == 3.44.* ]]; then
+ bash .github/patches/apply_flutter_3.44_web_patches.sh
+ fi
# https://rustdesk.com/docs/en/dev/build/web/
- name: Build web
diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml
index 41b9c0c13..7478bee9d 100644
--- a/.github/workflows/playground.yml
+++ b/.github/workflows/playground.yml
@@ -16,8 +16,8 @@ env:
FLUTTER_ELINUX_VERSION: "3.16.9"
TAG_NAME: "nightly"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
- VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
- VERSION: "1.4.9"
+ VCPKG_COMMIT_ID: "9e593bb18ea69cc5095e012465dcd675a822ed0d"
+ VERSION: "1.5.0"
NDK_VERSION: "r26d"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
@@ -271,7 +271,6 @@ jobs:
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
- libpam0g-dev \
libpulse-dev \
libva-dev \
libvdpau-dev \
@@ -284,7 +283,7 @@ jobs:
nasm \
yasm \
ninja-build \
- openjdk-11-jdk-headless \
+ openjdk-17-jdk-headless \
pkg-config \
tree \
wget
@@ -366,9 +365,9 @@ jobs:
- name: Build rustdesk
shell: bash
env:
- JAVA_HOME: /usr/lib/jvm/java-11-openjdk-amd64
+ JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
run: |
- export PATH=/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH
+ export PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH
# temporary use debug sign config
sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
case ${{ matrix.job.target }} in
diff --git a/.github/workflows/update-webpki-roots.yml b/.github/workflows/update-webpki-roots.yml
index e1efdb0d6..bf3150653 100644
--- a/.github/workflows/update-webpki-roots.yml
+++ b/.github/workflows/update-webpki-roots.yml
@@ -33,6 +33,10 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ # The root workspace lists libs/hbb_common as a member; without the
+ # submodule its manifest is missing and cargo cannot load the workspace.
+ submodules: recursive
- name: Update webpki-roots in all lockfiles
id: update
diff --git a/.gitignore b/.gitignore
index d2e09a906..f51a5b8cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,4 +55,6 @@ examples/**/target/
vcpkg_installed
flutter/lib/generated_plugin_registrant.dart
libsciter.dylib
-flutter/web/
\ No newline at end of file
+flutter/web/
+# libdrmtap is cloned at build time by build.py (not a submodule)
+/third_party/libdrmtap/
diff --git a/AGENTS.md b/AGENTS.md
index 8f558c959..fe8b73ec7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -61,12 +61,26 @@
* Do not make formatting-only changes.
* Keep naming/style consistent with nearby code.
+### Comments
+
+* Avoid comments unless they explain a non-obvious reason, constraint, or workaround.
+* Never restate what the code does; prefer clearer code instead.
+* If the code is self-explanatory, add no comment.
+
### Be minimally invasive
* Prefer purely additive changes: layer new (`#[cfg]`-gated) blocks or new functions around existing code instead of restructuring it. The ideal diff for a fix adds lines and modifies/deletes none.
* Do not extract or reshape existing code just to enable your new code; look for a mechanism that leaves existing lines untouched (e.g. hide/show an existing object instead of refactoring its construction into a helper for rebuilding).
+* Accept a little duplication over a restructure. A new function that repeats a few lines of an existing one is a better diff than reshaping the original so both can share it.
* Put new logic in self-contained functions in the module it belongs to (platform-specific logic in `src/platform/`, with `use` inside the function body to avoid churning shared import blocks). Call sites in shared files (`src/tray.rs`, `src/core_main.rs`, `src/server/connection.rs`, …) should be thin one-line hooks.
+## Reviewing a PR
+
+* Review only what the diff introduces. Verify ownership with `gh pr diff` before reporting a finding — if the offending lines are untouched context, it is a pre-existing problem, not this PR's.
+* List pre-existing problems in a separate section at the end, or leave out the ones that are not fatal. Never mix them into the findings the author has to fix.
+* Before re-reviewing, read the author's reply comments. Do not re-raise items they declined on scope grounds.
+* State a finding's consequence exactly: distinguish "the value is lost" from "the shortcut is inert but the value still saves".
+
## Localization (`src/lang/*.rs`)
Each file is a `HashMap`. Layout:
diff --git a/CLAUDE.md b/CLAUDE.md
index c31706425..43c994c2d 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1 +1 @@
-AGENTS.md
+@AGENTS.md
diff --git a/Cargo.lock b/Cargo.lock
index 93e1a6837..1746adc00 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -986,27 +986,6 @@ dependencies = [
"serde 1.0.228",
]
-[[package]]
-name = "bzip2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-dependencies = [
- "bzip2-sys",
- "libc",
-]
-
-[[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
-
[[package]]
name = "cacao"
version = "0.4.0-beta2"
@@ -1477,8 +1456,8 @@ dependencies = [
"compression-core",
"flate2",
"memchr",
- "zstd 0.13.1",
- "zstd-safe 7.1.0",
+ "zstd",
+ "zstd-safe",
]
[[package]]
@@ -1549,12 +1528,6 @@ dependencies = [
"unicode-xid 0.2.4",
]
-[[package]]
-name = "constant_time_eq"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
-
[[package]]
name = "constant_time_eq"
version = "0.2.6"
@@ -3074,9 +3047,8 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "fuser"
-version = "0.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53274f494609e77794b627b1a3cddfe45d675a6b2e9ba9c0fdc8d8eee2184369"
+version = "0.16.0"
+source = "git+https://github.com/rustdesk-org/fuser?branch=refact/tag-0.16.0-cargo-1.75.0#a3c0babe4a533f8dbcff5bce59ae7f2424b8d877"
dependencies = [
"libc",
"log",
@@ -3819,14 +3791,14 @@ dependencies = [
"toml 0.7.8",
"tungstenite",
"url",
- "users 0.11.0",
+ "users",
"uuid",
"webpki-roots 1.0.9",
"webrtc",
"whoami",
"winapi 0.3.9",
"x11 2.21.0",
- "zstd 0.13.1",
+ "zstd",
]
[[package]]
@@ -5960,37 +5932,6 @@ dependencies = [
"winapi 0.3.9",
]
-[[package]]
-name = "pam"
-version = "0.7.0"
-source = "git+https://github.com/rustdesk-org/pam#7bfd25510202cd269292cbdd7c71f3977a6fd762"
-dependencies = [
- "libc",
- "pam-macros",
- "pam-sys",
- "users 0.10.0",
-]
-
-[[package]]
-name = "pam-macros"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c94f3b9b97df3c6d4e51a14916639b24e02c7d15d1dba686ce9b1118277cb811"
-dependencies = [
- "proc-macro2 1.0.93",
- "quote 1.0.36",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "pam-sys"
-version = "1.0.0-alpha4"
-source = "git+https://github.com/rustdesk-org/pam-sys?branch=fix/v1.0.0-alpha4_gnuc_va_list#3337c9bb9a9c68d7497ec8c93cad2368c26091b7"
-dependencies = [
- "bindgen 0.59.2",
- "libc",
-]
-
[[package]]
name = "pango"
version = "0.18.3"
@@ -6058,35 +5999,12 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "password-hash"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
-dependencies = [
- "base64ct",
- "rand_core 0.6.4",
- "subtle",
-]
-
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
-[[package]]
-name = "pbkdf2"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
-dependencies = [
- "digest",
- "hmac",
- "password-hash",
- "sha2",
-]
-
[[package]]
name = "peeking_take_while"
version = "0.1.2"
@@ -7259,7 +7177,7 @@ dependencies = [
[[package]]
name = "rustdesk"
-version = "1.4.9"
+version = "1.5.0"
dependencies = [
"android-wakelock",
"android_logger",
@@ -7317,7 +7235,6 @@ dependencies = [
"once_cell",
"openssl",
"os-version",
- "pam",
"parity-tokio-ipc",
"percent-encoding",
"piet",
@@ -7366,12 +7283,11 @@ dependencies = [
"wol-rs",
"x11-clipboard 0.8.1",
"x11rb 0.12.0",
- "zip",
]
[[package]]
name = "rustdesk-portable-packer"
-version = "1.4.9"
+version = "1.5.0"
dependencies = [
"brotli",
"dirs 5.0.1",
@@ -8908,7 +8824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c4ae9724c5888c0417d2396037ed3b60665925624766416e3e342b6ba5dbd3f"
dependencies = [
"base32",
- "constant_time_eq 0.2.6",
+ "constant_time_eq",
"hmac",
"rand 0.8.5",
"sha1",
@@ -9353,16 +9269,6 @@ version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
-[[package]]
-name = "users"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa4227e95324a443c9fcb06e03d4d85e91aabe9a5a02aa818688b6918b6af486"
-dependencies = [
- "libc",
- "log",
-]
-
[[package]]
name = "users"
version = "0.11.0"
@@ -11158,52 +11064,13 @@ dependencies = [
"syn 2.0.98",
]
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "aes",
- "byteorder",
- "bzip2",
- "constant_time_eq 0.1.5",
- "crc32fast",
- "crossbeam-utils",
- "flate2",
- "hmac",
- "pbkdf2",
- "sha1",
- "time 0.3.36",
- "zstd 0.11.2+zstd.1.5.2",
-]
-
-[[package]]
-name = "zstd"
-version = "0.11.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
-dependencies = [
- "zstd-safe 5.0.2+zstd.1.5.2",
-]
-
[[package]]
name = "zstd"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
dependencies = [
- "zstd-safe 7.1.0",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "5.0.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
-dependencies = [
- "libc",
- "zstd-sys",
+ "zstd-safe",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index a7b2aca77..b1d9b7f91 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rustdesk"
-version = "1.4.9"
+version = "1.5.0"
authors = ["rustdesk "]
edition = "2021"
build= "build.rs"
@@ -30,7 +30,13 @@ default = ["use_dasp"]
hwcodec = ["scrap/hwcodec"]
vram = ["scrap/vram"]
mediacodec = ["scrap/mediacodec"]
-plugin_framework = []
+drm = ["scrap/drm"]
+# The display wake, as its OWN compile gate on top of `drm`. Everything else in the drm backend
+# READS (it captures a scanout); the wake WRITES, injecting one synthetic pointer event from the
+# root service so a compositor that idle-disabled its outputs re-enables them. That is a different
+# kind of operation and deserves a switch that can remove it from the binary entirely, without
+# giving up DRM capture: `--features drm` builds the capture path with no wake code compiled in.
+drm-wake = ["drm"]
linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"]
unix-file-copy-paste = [
"dep:x11-clipboard",
@@ -74,7 +80,6 @@ hex = "0.4"
chrono = "0.4"
cidr-utils = "0.5"
fon = "0.6"
-zip = "0.6"
shutdown_hooks = "0.1"
totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] }
stunclient = "0.4"
@@ -184,7 +189,6 @@ async-process = "1.7"
evdev = { git="https://github.com/rustdesk-org/evdev" }
dbus = "0.9"
dbus-crossroads = "0.5"
-pam = { git="https://github.com/rustdesk-org/pam" }
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true}
x11rb = {version = "0.12", features = ["all-extensions"], optional = true}
percent-encoding = {version = "2.3", optional = true}
@@ -205,7 +209,7 @@ android-wakelock = { git = "https://github.com/rustdesk-org/android-wakelock" }
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable", "libs/remote_printer"]
-exclude = ["vdi/host", "examples/custom_plugin"]
+exclude = ["vdi/host"]
# Patch libxdo-sys to use a stub implementation that doesn't require libxdo
# This allows building and running on systems without libxdo installed (e.g., Wayland-only)
diff --git a/Dockerfile b/Dockerfile
index f0e4e4a4a..e6c95ad52 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -19,7 +19,6 @@ RUN apt update -y && \
libxcb-shape0-dev \
libxcb-xfixes0-dev \
libasound2-dev \
- libpam0g-dev \
libpulse-dev \
make \
wget \
diff --git a/README.md b/README.md
index ae5c8d37c..a593a191f 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
Build •
Docker •
Structure •
- Snapshot
+ Screenshots
[Українська] | [česky] | [中文] | [Magyar] | [Español] | [فارسی] | [Français] | [Deutsch] | [Polski] | [Indonesian] | [Suomi] | [മലയാളം] | [日本語] | [Nederlands] | [Italiano] | [Русский] | [Português (Brasil)] | [Esperanto] | [한국어] | [العربي] | [Tiếng Việt] | [Dansk] | [Ελληνικά] | [Türkçe] | [Norsk] | [Română] We need your help to translate this README, RustDesk UI and RustDesk Doc to your native language
@@ -38,7 +38,7 @@ RustDesk welcomes contribution from everyone. See [CONTRIBUTING.md](docs/CONTRIB
## Dependencies
-Desktop versions use Flutter or Sciter (deprecated) for GUI, this tutorial is for Sciter only, since it is easier and more friendly to start. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building Flutter version.
+Desktop versions use Flutter or Sciter (deprecated) for GUI. This tutorial is for Sciter only, since it is easier and more friendly to start. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building the Flutter version.
Please download Sciter dynamic library yourself.
@@ -66,19 +66,19 @@ Please download Sciter dynamic library yourself.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -168,7 +168,6 @@ Please ensure that you run these commands from the root of the RustDesk reposito
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for desktop and mobile
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript for Flutter web client
## Screenshots
diff --git a/appimage/AppImageBuilder-aarch64.yml b/appimage/AppImageBuilder-aarch64.yml
index bad4e84db..2a0061bef 100644
--- a/appimage/AppImageBuilder-aarch64.yml
+++ b/appimage/AppImageBuilder-aarch64.yml
@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
- version: 1.4.9
+ version: 1.5.0
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:
@@ -58,7 +58,6 @@ AppDir:
- libpulse0
- packagekit-gtk3-module
- libcanberra-gtk3-module
- - libpam0g
- libdrm2
exclude:
- humanity-icon-theme
@@ -77,6 +76,13 @@ AppDir:
env:
GIO_MODULE_DIR: /lib64/gio/modules:/usr/lib/aarch64-linux-gnu/gio/modules:$APPDIR/usr/lib/aarch64-linux-gnu/gio/modules
GDK_BACKEND: x11
+ # AppRun sets these to "$APPDIR/...:$XDG_DATA_DIRS", and setting them at all suppresses the XDG
+ # defaults, so a host that leaves them unset loses /usr/share and /etc/xdg. gdk-pixbuf 2.43+
+ # (Arch, Fedora) then finds no glycin loaders and every PNG decode fails, aborting on the first
+ # remote cursor. The host value goes last: unset it expands to an empty element, which GLib
+ # resolves against the CWD, and that must not outrank the defaults below.
+ XDG_DATA_DIRS: $APPDIR/usr/local/share:$APPDIR/usr/share:/usr/local/share:/usr/share:$XDG_DATA_DIRS
+ XDG_CONFIG_DIRS: $APPDIR/etc/xdg:/etc/xdg:$XDG_CONFIG_DIRS
APPDIR_LIBRARY_PATH: /lib64:/usr/lib/aarch64-linux-gnu:$APPDIR/lib/aarch64-linux-gnu:$APPDIR/lib/aarch64-linux-gnu/security:$APPDIR/lib/systemd:$APPDIR/usr/lib/aarch64-linux-gnu:$APPDIR/usr/lib/aarch64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gtk-3.0/3.0.0/immodules:$APPDIR/usr/lib/aarch64-linux-gnu/gtk-3.0/3.0.0/printbackends:$APPDIR/usr/lib/aarch64-linux-gnu/krb5/plugins/preauth:$APPDIR/usr/lib/aarch64-linux-gnu/libcanberra-0.30:$APPDIR/usr/lib/aarch64-linux-gnu/pulseaudio:$APPDIR/usr/lib/aarch64-linux-gnu/sasl2:$APPDIR/usr/lib/aarch64-linux-gnu/vdpau:$APPDIR/usr/share/rustdesk/lib:$APPDIR/lib/aarch64
GST_PLUGIN_PATH: /lib64/gstreamer-1.0:/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0
GST_PLUGIN_SYSTEM_PATH: /lib64/gstreamer-1.0:/usr/lib/aarch64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/aarch64-linux-gnu/gstreamer-1.0
diff --git a/appimage/AppImageBuilder-x86_64.yml b/appimage/AppImageBuilder-x86_64.yml
index 7cd52b89a..49ede99eb 100644
--- a/appimage/AppImageBuilder-x86_64.yml
+++ b/appimage/AppImageBuilder-x86_64.yml
@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
- version: 1.4.9
+ version: 1.5.0
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:
@@ -61,7 +61,6 @@ AppDir:
- libpulse0
- packagekit-gtk3-module
- libcanberra-gtk3-module
- - libpam0g
- libdrm2
exclude:
- humanity-icon-theme
@@ -80,6 +79,13 @@ AppDir:
env:
GIO_MODULE_DIR: /lib64/gio/modules:/usr/lib/x86_64-linux-gnu/gio/modules:$APPDIR/usr/lib/x86_64-linux-gnu/gio/modules
GDK_BACKEND: x11
+ # AppRun sets these to "$APPDIR/...:$XDG_DATA_DIRS", and setting them at all suppresses the XDG
+ # defaults, so a host that leaves them unset loses /usr/share and /etc/xdg. gdk-pixbuf 2.43+
+ # (Arch, Fedora) then finds no glycin loaders and every PNG decode fails, aborting on the first
+ # remote cursor. The host value goes last: unset it expands to an empty element, which GLib
+ # resolves against the CWD, and that must not outrank the defaults below.
+ XDG_DATA_DIRS: $APPDIR/usr/local/share:$APPDIR/usr/share:/usr/local/share:/usr/share:$XDG_DATA_DIRS
+ XDG_CONFIG_DIRS: $APPDIR/etc/xdg:/etc/xdg:$XDG_CONFIG_DIRS
APPDIR_LIBRARY_PATH: /lib64:/usr/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu/security:$APPDIR/lib/systemd:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules:$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/printbackends:$APPDIR/usr/lib/x86_64-linux-gnu/krb5/plugins/preauth:$APPDIR/usr/lib/x86_64-linux-gnu/libcanberra-0.30:$APPDIR/usr/lib/x86_64-linux-gnu/pulseaudio:$APPDIR/usr/lib/x86_64-linux-gnu/sasl2:$APPDIR/usr/lib/x86_64-linux-gnu/vdpau:$APPDIR/usr/share/rustdesk/lib:$APPDIR/lib/x86_64
GST_PLUGIN_PATH: /lib64/gstreamer-1.0:/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0
GST_PLUGIN_SYSTEM_PATH: /lib64/gstreamer-1.0:/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0
diff --git a/build.py b/build.py
index 957961857..4f1953662 100755
--- a/build.py
+++ b/build.py
@@ -1,16 +1,25 @@
#!/usr/bin/env python3
import os
+import glob
+import contextlib
import pathlib
import platform
import zipfile
import urllib.request
import shutil
import hashlib
+import re
+import subprocess
import argparse
import sys
from pathlib import Path
+# Captured at import, while cwd is still the repo root: before Python 3.9 the main script's __file__
+# stays relative (bpo-20443), so abspath() re-resolves it against the cwd -- and the ubuntu18.04
+# packaging container runs 3.6 and chdir's into flutter/ before it reaches the libdrmtap code.
+REPO_ROOT = os.path.dirname(os.path.abspath(__file__))
+
windows = platform.platform().startswith('Windows')
osx = platform.platform().startswith(
'Darwin') or platform.platform().startswith("macOS")
@@ -130,6 +139,19 @@ def make_parser():
action='store_true',
help='Build with unix file copy paste feature'
)
+ parser.add_argument(
+ '--drm',
+ action='store_true',
+ help='Linux only: build the DRM/KMS capture backend (bundles libdrmtap.so, '
+ 'dlopen-ed in-process by the root service). Off by default.'
+ )
+ parser.add_argument(
+ '--print-features',
+ action='store_true',
+ help='Print the cargo feature list these flags select, and exit without building. For a '
+ 'caller that runs its own cargo line and then packages with --skip-cargo: it can ask '
+ 'for the list rather than repeat it, so the two cannot drift.'
+ )
parser.add_argument(
'--skip-cargo',
action='store_true',
@@ -272,6 +294,24 @@ def external_resources(flutter, args, res_dir):
shutil.copytree(f, f'{flutter_build_dir_2}{f.stem}')
+def linux_packaging_branch():
+ """Which packaging path `main()` will take on THIS host.
+
+ MUST mirror the elif chain in main() (pacman / yum / zypper / else), and exists so `--drm` can
+ refuse a branch that is not drm-aware instead of silently producing a stock-named package with
+ the capture backend compiled in. Only the final `deb` branch reaches `build_flutter_deb`, which
+ is what bundles libdrmtap, renames the package, adds Conflicts/Provides and asserts the staged
+ binary really is a drm build.
+ """
+ if os.path.isfile('/usr/bin/pacman'):
+ return 'pacman'
+ if os.path.isfile('/usr/bin/yum'):
+ return 'yum'
+ if os.path.isfile('/usr/bin/zypper'):
+ return 'zypper'
+ return 'deb'
+
+
def get_features(args):
features = ['inline'] if not args.flutter else []
if args.hwcodec:
@@ -282,6 +322,30 @@ def get_features(args):
features.append('flutter')
if args.unix_file_copy_paste:
features.append('unix-file-copy-paste')
+ if args.drm:
+ # Say so rather than quietly handing back a stock build: the backend is Linux-only, so on
+ # any other host the flag cannot be honoured and the resulting binary would look like a
+ # DRM build without being one.
+ if windows or osx:
+ raise Exception('--drm is Linux only')
+ # And only on the deb branch. The other three Linux paths (pacman/yum/zypper) package
+ # straight from `target/release` without bundling libdrmtap, without the rename, without
+ # Conflicts/Provides and without assert_staged_binary_is_drm() -- so they would emit a
+ # package NAMED `rustdesk` carrying the consent-bypass backend and the root-side uinput
+ # injection. The separate package name is the informed consent this feature rests on, so
+ # refuse rather than ship a stock-named build of it.
+ branch = linux_packaging_branch()
+ if branch != 'deb':
+ raise Exception(
+ f'--drm is only supported on the deb packaging path; this host would package via '
+ f'{branch}, which cannot bundle libdrmtap or name the package distinctly')
+ features.append('drm')
+ # The display wake is its own compile gate on top of `drm`, and the unattended package is
+ # exactly where it belongs: that variant exists to reach a machine nobody is sitting at,
+ # and a machine whose screen went dark is the case it is for. Dropping `drm-wake` from
+ # this line builds the same capture backend with no wake code in the binary at all.
+ # It is ALSO switchable at runtime; see OPTION_ENABLE_DRM_DISPLAY_WAKE.
+ features.append('drm-wake')
if osx:
if args.screencapturekit:
features.append('screencapturekit')
@@ -300,7 +364,7 @@ Version: %s
Architecture: %s
Maintainer: rustdesk
Homepage: https://rustdesk.com
-Depends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s
+Depends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, gstreamer1.0-pipewire%s
Recommends: libayatana-appindicator3-1
Description: A remote control software.
@@ -316,6 +380,322 @@ def ffi_bindgen_function_refactor():
'sed -i "s/ffi.NativeFunction= floor
+ if not accepted:
+ raise Exception(
+ f'the libdrmtap being packaged is {so_ver[0]}.{so_ver[1]}.{so_ver[2]}, which the '
+ f'runtime loader would REFUSE: drmtap_dl.rs accepts exactly major {major}, minor '
+ f'{minor}, patch >= {floor[1]}. Shipping it produces a deb whose DRM capture can never '
+ 'start. Move the build pin and the gate together, or fix whichever one is wrong.')
+ print(f'[drm] libdrmtap {so_ver[0]}.{so_ver[1]}.{so_ver[2]} satisfies the runtime ABI gate '
+ f'(major {major}, minor {minor}, patch >= {floor[1]})')
+
+
+def stage_libdrmtap_into_deb(so_path):
+ # Put the built libdrmtap object plus its soname symlink into the staged deb. Only the soname
+ # symlink is needed: libdrmtap is resolved by ABSOLUTE path (/usr/lib/rustdesk/libdrmtap.so.0) at
+ # the in-process dlopen site (drmtap_dl.rs), so the deb does NOT drop /usr/lib/rustdesk into the
+ # system-wide /etc/ld.so.conf.d search path, which would let this private library shadow a system
+ # library for every binary on the host (Debian Policy 10.2 forbids that). No ld.so.conf.d drop-in
+ # and no ldconfig trigger are shipped, so the stock postinst is used unchanged.
+ assert_so_satisfies_the_runtime_abi_gate(so_path)
+ so_basename = os.path.basename(so_path)
+ system2('mkdir -p tmpdeb/usr/lib/rustdesk')
+ # Quoted: so_path comes from the repo root or from DRMTAP_PREBUILT_DIR, either of which can
+ # contain a space, and an unquoted interpolation would split the argument and fail obscurely.
+ system2(f'cp "{so_path}" tmpdeb/usr/lib/rustdesk/')
+ system2(f'ln -sf "{so_basename}" tmpdeb/usr/lib/rustdesk/libdrmtap.so.0')
+
+
+def _max_glibc_minor(path):
+ # Read from .dynstr rather than via objdump so packaging needs no binutils; chunked because
+ # librustdesk.so is ~45 MB.
+ best = 0
+ with open(path, 'rb') as f:
+ tail = b''
+ while True:
+ chunk = f.read(1 << 20)
+ if not chunk:
+ return best
+ for m in re.finditer(rb'GLIBC_2\.(\d+)', tail + chunk):
+ best = max(best, int(m.group(1)))
+ tail = chunk[-16:]
+
+
+def measured_glibc_floor():
+ # libdrmtap is built on a newer base than the rest of the deb, so the floor is whichever staged
+ # object is higher -- and it moves whenever either base does.
+ paths = [p for p in glob.glob('tmpdeb/usr/lib/rustdesk/libdrmtap.so.0.*')
+ + glob.glob('tmpdeb/usr/share/rustdesk/lib/librustdesk.so')
+ + glob.glob('tmpdeb/usr/share/rustdesk/rustdesk')
+ if os.path.isfile(p) and not os.path.islink(p)]
+ minor = max((_max_glibc_minor(p) for p in paths), default=0)
+ if not minor:
+ raise Exception(
+ f'could not measure a GLIBC_2.x floor from any staged object ({paths or "none found"}); '
+ 'refusing to ship the unattended-wayland variant with an undeclared libc6 floor, which '
+ 'is what lets it install on a host where libdrmtap can never load')
+ return f'2.{minor}'
+
+
+def retarget_control_to_drm_variant():
+ # Rewrite the control file that generate_control_file just produced, instead of parameterizing that
+ # function: the stock packaging path stays exactly as upstream wrote it, and everything specific to
+ # this variant lives here. The variant installs the same files as the stock package, so it must
+ # conflict with and replace it: you install one or the other, never both. It also needs libdrmtap's
+ # own runtime deps, which the stock package has no reason to carry.
+ path = '../res/DEBIAN/control'
+ floor = measured_glibc_floor()
+ print(f'[drm] {DRM_PACKAGE_NAME} libc6 floor measured at {floor}')
+ with open(path) as f:
+ lines = f.readlines()
+ out = []
+ for line in lines:
+ if line.startswith('Package: rustdesk'):
+ out.append(f'Package: {DRM_PACKAGE_NAME}\n')
+ out.append('Conflicts: rustdesk\nReplaces: rustdesk\nProvides: rustdesk\n')
+ elif line.startswith('Depends:'):
+ # 2.4.101 is where drmModeGetFB2 landed; below it libdrmtap loads and can never capture.
+ out.append(line.rstrip('\n') + ', libdrm2 (>= 2.4.101), libegl1, libgles2, '
+ f'libc6 (>= {floor})\n')
+ else:
+ out.append(line)
+ body = ''.join(out)
+ # Fail loudly rather than silently shipping a package that says `rustdesk`: a stock control file
+ # that stopped matching either anchor would otherwise produce a variant deb wearing the stock name.
+ if f'Package: {DRM_PACKAGE_NAME}\n' not in body or 'libegl1' not in body:
+ raise Exception(f'could not retarget {path} to the drm variant; upstream control layout changed')
+ with open(path, 'w') as f:
+ f.write(body)
+
+
def build_flutter_deb(version, features):
if not skip_cargo:
system2(f'cargo build --locked --features {features} --lib --release')
@@ -324,8 +704,6 @@ def build_flutter_deb(version, features):
system2('flutter build linux --release')
system2('mkdir -p tmpdeb/usr/bin/')
system2('mkdir -p tmpdeb/usr/share/rustdesk')
- system2('mkdir -p tmpdeb/etc/rustdesk/')
- system2('mkdir -p tmpdeb/etc/pam.d/')
system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/256x256/apps/')
system2('mkdir -p tmpdeb/usr/share/icons/hicolor/scalable/apps/')
@@ -344,17 +722,24 @@ def build_flutter_deb(version, features):
'cp ../res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
system2(
'cp ../res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
- system2(
- 'cp ../res/startwm.sh tmpdeb/etc/rustdesk/')
- system2(
- 'cp ../res/xorg.conf tmpdeb/etc/rustdesk/')
- system2(
- 'cp ../res/pam.d/rustdesk.debian tmpdeb/etc/pam.d/rustdesk')
system2(
"echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
+ # Bundle libdrmtap.so only when this build actually enabled the `drm` feature, so stock packages
+ # stay exactly what they were. The root service dlopens it in-process by absolute path.
+ # `features` is the comma-joined string, so split it: a bare substring test would also match any
+ # future feature merely containing "drm" (drm-lease, vaapi-drm) and rename the deb to the
+ # consent-bypass variant without --drm ever being passed.
+ ships_so = 'drm' in features.split(',')
+ if ships_so:
+ # Same artifact assertion as the --package path. Under --skip-cargo nothing here rebuilt the
+ # binary, so `features` says what was ASKED for while the staged bundle can be anything.
+ assert_staged_binary_is_drm()
+ stage_libdrmtap_into_deb(build_libdrmtap_so())
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
+ if ships_so:
+ retarget_control_to_drm_variant()
system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/')
md5_file_folder("tmpdeb/")
system2('dpkg-deb -b tmpdeb rustdesk.deb;')
@@ -362,10 +747,68 @@ def build_flutter_deb(version, features):
system2('/bin/rm -rf tmpdeb/')
system2('/bin/rm -rf ../res/DEBIAN/control')
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
+ if ships_so:
+ # Named apart from the stock package so installing the consent-free variant is a deliberate act.
+ os.rename('../rustdesk-%s.deb' % version, f'../{DRM_PACKAGE_NAME}-{version}.deb')
os.chdir("..")
-def build_deb_from_folder(version, binary_folder):
+DRMTAP_DLOPEN_MARKER = b'/usr/lib/rustdesk/libdrmtap.so.0'
+# Present only when `drm-wake` is compiled in: the runtime option constant is itself
+# #[cfg(feature = "drm-wake")] (src/ipc/drm.rs). The dlopen marker above cannot stand in for it -
+# `--features drm` alone produces a binary that carries the dlopen path and NO wake code, and that
+# is exactly the deb this assertion is here to refuse.
+DRMTAP_WAKE_MARKER = b'enable-drm-display-wake'
+
+
+def _carries_drmtap_marker(path, marker=DRMTAP_DLOPEN_MARKER):
+ # Chunked, with an overlap of len(marker)-1 so the marker cannot be missed at a chunk boundary:
+ # librustdesk.so is ~45 MB and there is no reason to hold it all in memory, and the `with`
+ # closes deterministically instead of relying on refcounting.
+ with open(path, 'rb') as f:
+ tail = b''
+ while True:
+ chunk = f.read(1 << 20)
+ if not chunk:
+ return False
+ if marker in tail + chunk:
+ return True
+ tail = chunk[-(len(marker) - 1):]
+
+
+def assert_staged_binary_is_drm():
+ """The staged BINARY must really be a drm build before it is named the unattended-wayland
+ variant. That package conflicts with and replaces the stock one, so shipping a stock binary
+ under that name produces something that can never capture and cannot be installed alongside
+ what it replaced. The marker is the absolute dlopen path from drmtap_dl.rs, present only when
+ the feature is compiled in -- assert what was produced, not what was asked for.
+
+ Called from BOTH packaging paths. It used to guard only one of them, and `--skip-cargo` (which
+ is how CI packages) reaches the other, where nothing had rebuilt the binary at all.
+ """
+ binaries = [p for p in glob.glob('tmpdeb/usr/share/rustdesk/lib/librustdesk.so')
+ + glob.glob('tmpdeb/usr/share/rustdesk/rustdesk') if os.path.isfile(p)]
+ if not any(_carries_drmtap_marker(p) for p in binaries):
+ raise Exception(
+ f'--drm was requested but the staged bundle does not look like a drm build (no '
+ f'{DRMTAP_DLOPEN_MARKER.decode()} dlopen path in {binaries or "any staged binary"}); '
+ 'refusing to package it as the unattended-wayland variant, which conflicts with and '
+ 'replaces the stock package but could never capture')
+ # And the WAKE half. `--drm` enables `drm-wake` too (see get_features), and the deb is named and
+ # documented as the variant that can reach a machine whose screen has gone dark. The dlopen
+ # marker above does not distinguish them: `--features drm` alone carries it and has no wake code
+ # at all. Asserting only the first half is how a deb can be named for a feature it does not have.
+ if not any(_carries_drmtap_marker(p, DRMTAP_WAKE_MARKER) for p in binaries):
+ raise Exception(
+ f'--drm was requested but the staged binary has no {DRMTAP_WAKE_MARKER.decode()} '
+ f'marker in {binaries or "any staged binary"}, so it was built without `drm-wake`; '
+ 'refusing to package it as the unattended-wayland variant, which is named and '
+ 'documented as the build that can wake an idle-disabled display. If this fired under '
+ '--skip-cargo, the cargo line that produced the bundle is missing the feature: '
+ '--features ...,drm,drm-wake')
+
+
+def build_deb_from_folder(version, binary_folder, want_drm=False):
os.chdir('flutter')
system2('mkdir -p tmpdeb/usr/bin/')
system2('mkdir -p tmpdeb/usr/share/rustdesk')
@@ -389,9 +832,53 @@ def build_deb_from_folder(version, binary_folder):
'cp ../res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
system2(
"echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
+ # Where the capture library comes from for a `--package --drm` build. Two shapes are
+ # supported, because two exist in practice: a bundle that already carries libdrmtap.so.0.*
+ # (someone staged it, e.g. a CI artifact), and a plain bundle, which is what every build path
+ # here actually produces -- the flutter deb builds the library straight into the staged deb, so
+ # nothing ever puts it inside the bundle folder. Demanding it in the bundle made this flag
+ # combination impossible to satisfy.
+ bundled_glob = glob.glob('tmpdeb/usr/share/rustdesk/libdrmtap.so.0.*')
+ bundle_carries_so = any(os.path.isfile(p) and not os.path.islink(p) for p in bundled_glob)
+ # The variant must be decided by the EXPLICIT --drm request, not merely by what happens to be
+ # staged: a bundle that carries the .so must NOT be shipped as the consent-bypass variant when
+ # --drm was never passed.
+ if bundle_carries_so and not want_drm:
+ raise Exception(
+ 'the staged bundle carries libdrmtap.so.0.* but --drm was not passed; refusing '
+ 'to silently ship the consent-bypass unattended-wayland variant (pass --drm to '
+ 'build it deliberately)')
+ if want_drm:
+ # Whichever shape we are in, the staged BINARY must really be a drm build. This is the
+ # property the old presence-of-the-.so test stood in for, badly: a stock binary packaged as
+ # the unattended-wayland variant would carry the consent-bypass name, conflict with and
+ # replace the stock package, and never be able to capture. The marker is the absolute
+ # dlopen path from drmtap_dl.rs, present only when the feature is compiled in -- the same
+ # kind of artifact assertion as _assert_so_has_egl, and for the same reason: assert what
+ # was produced, not what was asked for.
+ assert_staged_binary_is_drm()
+ if bundle_carries_so:
+ so = _single_real_so(bundled_glob, 'the staged --drm bundle')
+ # The THIRD artifact source, and the last one that was missing the check: --package
+ # takes the .so straight out of a bundle somebody else produced, so it has the same
+ # exposure as DRMTAP_PREBUILT_DIR (see the comment on that branch). A CPU-only stub
+ # would ship, the loader would accept it, and capture would degrade to PipeWire
+ # without a word.
+ _assert_so_has_egl(so)
+ stage_libdrmtap_into_deb(so)
+ system2(f'rm -f "{so}"')
+ system2('rm -f tmpdeb/usr/share/rustdesk/libdrmtap.so tmpdeb/usr/share/rustdesk/libdrmtap.so.0')
+ else:
+ # Build it here, exactly as the flutter deb path does (build_libdrmtap_so asserts the
+ # EGL backend itself). The library is independent of the staged binary.
+ stage_libdrmtap_into_deb(build_libdrmtap_so())
system2('mkdir -p tmpdeb/DEBIAN')
generate_control_file(version)
+ # Keyed on the EXPLICIT request, not on what happened to be staged: by here a --drm build has
+ # its library in tmpdeb whichever of the two shapes it came from.
+ if want_drm:
+ retarget_control_to_drm_variant()
system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/')
md5_file_folder("tmpdeb/")
system2('dpkg-deb -b tmpdeb rustdesk.deb;')
@@ -399,6 +886,8 @@ def build_deb_from_folder(version, binary_folder):
system2('/bin/rm -rf tmpdeb/')
system2('/bin/rm -rf ../res/DEBIAN/control')
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
+ if want_drm:
+ os.rename('../rustdesk-%s.deb' % version, f'../{DRM_PACKAGE_NAME}-{version}.deb')
os.chdir("..")
@@ -473,6 +962,19 @@ def main():
parser = make_parser()
args = parser.parse_args()
+ # Before anything with a side effect: this is a query, and a caller uses it to build the very
+ # binary it will then package. `get_features` stays the single definition of what a flag
+ # combination means; a caller that hardcodes the list instead is one edit away from compiling
+ # something other than what it ships.
+ if args.print_features:
+ # stdout carries the list and nothing else, so a caller can use it directly in a command
+ # substitution. `get_features` prints a human-readable line of its own; send that to stderr
+ # for this call rather than silencing it, which would change what every other path prints.
+ with contextlib.redirect_stdout(sys.stderr):
+ feats = ','.join(get_features(args))
+ print(feats)
+ return
+
if os.path.exists(exe_path):
os.unlink(exe_path)
if os.path.isfile('/usr/bin/pacman'):
@@ -488,7 +990,7 @@ def main():
portable = args.portable
package = args.package
if package:
- build_deb_from_folder(version, package)
+ build_deb_from_folder(version, package, args.drm)
return
res_dir = 'resources'
external_resources(flutter, args, res_dir)
@@ -622,13 +1124,7 @@ def main():
'cp res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
system2(
'cp res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
- os.system('mkdir -p tmpdeb/etc/rustdesk/')
- os.system('cp -a res/startwm.sh tmpdeb/etc/rustdesk/')
- os.system('mkdir -p tmpdeb/etc/X11/rustdesk/')
- os.system('cp res/xorg.conf tmpdeb/etc/X11/rustdesk/')
os.system('cp -a DEBIAN/* tmpdeb/DEBIAN/')
- os.system('mkdir -p tmpdeb/etc/pam.d/')
- os.system('cp pam.d/rustdesk.debian tmpdeb/etc/pam.d/rustdesk')
system2('strip tmpdeb/usr/bin/rustdesk')
system2('mkdir -p tmpdeb/usr/share/rustdesk')
system2('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/share/rustdesk/')
diff --git a/build.rs b/build.rs
index 92fb1f4b4..ec87831c0 100644
--- a/build.rs
+++ b/build.rs
@@ -72,7 +72,6 @@ fn install_android_deps() {
path.join("lib").to_str().unwrap()
);
println!("cargo:rustc-link-lib=ndk_compat");
- println!("cargo:rustc-link-lib=oboe");
println!("cargo:rustc-link-lib=c++");
println!("cargo:rustc-link-lib=OpenSLES");
}
diff --git a/docs/CONTRIBUTING-ID.md b/docs/CONTRIBUTING-ID.md
index cdff6c01f..b5ab29f46 100644
--- a/docs/CONTRIBUTING-ID.md
+++ b/docs/CONTRIBUTING-ID.md
@@ -24,7 +24,7 @@ Untuk instruksi Git yang lebih lanjut, cek disini [GitHub workflow 101](https://
## Tindakan
-
+
## Komunikasi
diff --git a/docs/CONTRIBUTING-IT.md b/docs/CONTRIBUTING-IT.md
index a3a5fd2b6..f3ea9fbb7 100644
--- a/docs/CONTRIBUTING-IT.md
+++ b/docs/CONTRIBUTING-IT.md
@@ -30,7 +30,7 @@ Per istruzioni specifiche su git, vedi [Workflow GitHub - 101](https://github.co
## Condotta
-https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT-IT.md
+https://github.com/rustdesk/rustdesk/blob/master/docs/CODE_OF_CONDUCT.md
## Comunicazioni
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 31fd632e6..43bbf27a6 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -1,6 +1,6 @@
# Contributing to RustDesk
-RustDesk welcomes contribution from everyone. Here are the guidelines if you are
+RustDesk welcomes contributions from everyone. Here are the guidelines if you are
thinking of helping us:
## Contributions
diff --git a/docs/README-AR.md b/docs/README-AR.md
index 5aa09da88..6996ff7c3 100644
--- a/docs/README-AR.md
+++ b/docs/README-AR.md
@@ -160,7 +160,6 @@ RustDesk يرجى التأكد من أنك تنفذ هذه الأوامر من
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: أو المنقول عن بُعد (TCP hole punching) انتظر الاتصال المباشر [rustdesk-server](https://github.com/rustdesk/rustdesk-server) الإتصال ب
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: رمز خاص بكل منصة
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: رمز الهاتف المحمول
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**:Flutter لعميل الويب الخاص ب Javascript
## لقطات
diff --git a/docs/README-CS.md b/docs/README-CS.md
index b208414fe..2555bd8dd 100644
--- a/docs/README-CS.md
+++ b/docs/README-CS.md
@@ -144,7 +144,6 @@ Ujistěte se, že tyto příkazy spouštíte z kořenového adresáře RustDesk,
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: komunikace s [rustdesk-server](https://github.com/rustdesk/rustdesk-server), očekávání vzdálených příméhých („proděrováváním“ TCP) nebo předávaných (relay) spojení
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: zdrojové kódy, specifické pro jednotlivé platformy
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: zdrojové kódy pro použití s aplikačním rámcem (framework) Flutter pro mobilní platformy
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Javascript pro Flutter webový klient
## Ukázky
diff --git a/docs/README-DE.md b/docs/README-DE.md
index ba8894411..91ba5a08c 100644
--- a/docs/README-DE.md
+++ b/docs/README-DE.md
@@ -66,19 +66,19 @@ Bitte laden Sie die dynamische Bibliothek Sciter selbst herunter.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -168,7 +168,6 @@ Bitte stellen Sie sicher, dass Sie diese Befehle im Stammverzeichnis des RustDes
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Mit [rustdesk-server](https://github.com/rustdesk/rustdesk-server) kommunizieren, warten auf direkte (TCP hole punching) oder weitergeleitete Verbindung
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: Plattformspezifischer Code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter-Code für Handys
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript für Flutter-Webclient
## Screenshots
diff --git a/docs/README-ES.md b/docs/README-ES.md
index da939bd7b..bdf099ffd 100644
--- a/docs/README-ES.md
+++ b/docs/README-ES.md
@@ -62,19 +62,19 @@ Por favor descarga la librería dinámica de Sciter tú mismo.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -163,7 +163,6 @@ Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunicación con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), esperar la conexión remota directa ("TCP hole punching") o conexión indirecta ("relayed")
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter, código para moviles
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Javascript para el cliente web Flutter
> [!Precaución]
> **Descargo de responsabilidad por uso indebido:**
diff --git a/docs/README-FA.md b/docs/README-FA.md
index a0645e02b..a0bef5acb 100644
--- a/docs/README-FA.md
+++ b/docs/README-FA.md
@@ -146,7 +146,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for mobile
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Javascript for Flutter web client
## تصاویر محیط نرمافزار
diff --git a/docs/README-GR.md b/docs/README-GR.md
index 8b0276bf8..1346bedbb 100644
--- a/docs/README-GR.md
+++ b/docs/README-GR.md
@@ -158,7 +158,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for mobile
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter web client
## Στιγμιότυπα
diff --git a/docs/README-HU.md b/docs/README-HU.md
index 82d1d5550..fc74d4bfe 100644
--- a/docs/README-HU.md
+++ b/docs/README-HU.md
@@ -48,7 +48,7 @@ A telefonos verziók Flutter-t hasznának. Később lehetséges hogy Sciterről
- Futtasd a `cargo run` parancsot
-## [Építés](https://rustdesk.com/docs/hu/dev/build/)
+## [Építés](https://rustdesk.com/docs/en/dev/build/)
## Hogyan építs Linuxon
@@ -150,7 +150,6 @@ Kérlek mindenképpen nézd meg hogy ezeket a parancsokat a root RustDesk mappá
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for mobile
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Javascript for Flutter web client
## Képernyőképek
diff --git a/docs/README-IT.md b/docs/README-IT.md
index 0393ee6c7..ee5351b6c 100644
--- a/docs/README-IT.md
+++ b/docs/README-IT.md
@@ -162,7 +162,6 @@ Assicurati di eseguire questi comandi dalla radice del repository RustDesk, altr
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: comunica con [rustdesk-server](https://github.com/rustdesk/rustdesk-server), attende la connessione remota diretta (TCP hole punching) oppure indiretta (relayed)
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: codice specifico della piattaforma
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: codice Flutter per desktop e mobile
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript per client web Flutter
> [!Attenzione]
> **Dichiarazione di non responsabilità per uso improprio:**
diff --git a/docs/README-JP.md b/docs/README-JP.md
index c9f75640b..6abeae5c0 100644
--- a/docs/README-JP.md
+++ b/docs/README-JP.md
@@ -166,7 +166,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server)と通信し、リモートの直接接続(TCPホールパンチング)や中継接続を担う。
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: プラットフォーム固有のコード
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: デスクトップとモバイル向けのFlutterコード
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutterウェブクライアント向けのJavaScript
> [!注意]
> **:不正使用に関する免責事項**
diff --git a/docs/README-KR.md b/docs/README-KR.md
index d7d3cf43e..687ba24e6 100644
--- a/docs/README-KR.md
+++ b/docs/README-KR.md
@@ -66,19 +66,19 @@ Sciter 동적 라이브러리를 직접 다운로드하세요.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -168,7 +168,6 @@ RustDesk 리포지토리의 루트에서 이러한 명령을 실행하고 있는
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server)와 통신, 원격 다이렉트 (TCP 홀 펀칭) 또는 릴레이 연결 대기
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: 플랫폼별 코드
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: 데스크톱 및 모바일용 Flutter 코드
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: Flutter 웹 클라이언트용 JavaScript
## 스크린샷
diff --git a/docs/README-NO.md b/docs/README-NO.md
index 1352e8aed..609795996 100644
--- a/docs/README-NO.md
+++ b/docs/README-NO.md
@@ -62,19 +62,19 @@ Venligst last ned Sciters dynamiske bibliotek selv.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -163,7 +163,6 @@ Venligst pass på att du kjører disse kommandoene fra roten av RustDesk reposit
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Kommunikasjon med [rustdesk-server](https://github.com/rustdesk/rustdesk-server), vent på direkte fjernstyring (TCP hulling) eller vidresendt tilkobling
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform spesefik kode
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter kode for desktop og mobil
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter nettsted klient
## Skjermbilder
diff --git a/docs/README-PL.md b/docs/README-PL.md
index 437682a9c..4b48b0996 100644
--- a/docs/README-PL.md
+++ b/docs/README-PL.md
@@ -155,7 +155,6 @@ Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium Ru
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Komunikacja z [rustdesk-server](https://github.com/rustdesk/rustdesk-server), czekanie na bezpośrednie (odpytywanie TCP) lub przekazywane połączenie
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: kod specyficzny dla danej platformy
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: kod Flutter dla urządzeń mobilnych
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript dla Flutter - klient web
## Zrzuty ekranu
diff --git a/docs/README-PTBR.md b/docs/README-PTBR.md
index 2b4c1e6c2..332967ea2 100644
--- a/docs/README-PTBR.md
+++ b/docs/README-PTBR.md
@@ -64,19 +64,19 @@ Por favor, faça o download da biblioteca dinâmica do Sciter por conta própria
### Ubuntu 18 (Debian 10)
```sh
-sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -166,7 +166,6 @@ Certifique-se de executar esses comandos a partir da raiz do repositório do Rus
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Comunica-se com o [rustdesk-server](https://github.com/rustdesk/rustdesk-server), aguarda por conexão remota direta (perfuração de túnel TCP / hole punching) ou retransmitida.
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: código específico de cada plataforma.
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: código Flutter para desktop e dispositivos móveis.
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript para o cliente web do Flutter.
## Capturas de Tela
diff --git a/docs/README-RO.md b/docs/README-RO.md
index be7ecf164..0f2f17466 100644
--- a/docs/README-RO.md
+++ b/docs/README-RO.md
@@ -66,19 +66,19 @@ Te rugăm să descarci singur librăria dinamică Sciter.
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -168,7 +168,6 @@ Asigură-te că rulezi aceste comenzi din rădăcina repository-ului RustDesk, a
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: comunică cu [rustdesk-server](https://github.com/rustdesk/rustdesk-server), așteaptă conexiune directă remote (TCP hole punching) sau prin relay
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: cod specific platformei
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: cod Flutter pentru desktop și mobil
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript pentru clientul Flutter web
## Capturi de ecran
diff --git a/docs/README-RU.md b/docs/README-RU.md
index 928faad07..e3e97d8ca 100644
--- a/docs/README-RU.md
+++ b/docs/README-RU.md
@@ -59,7 +59,7 @@ RustDesk приветствует вклад каждого. Ознакомьт
- Выполните команду `cargo run`
-## [Сборка](https://rustdesk.com/docs/ru/dev/build/)
+## [Сборка](https://rustdesk.com/docs/en/dev/build/)
## Как собрать на Linux
@@ -68,19 +68,19 @@ RustDesk приветствует вклад каждого. Ознакомьт
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -170,7 +170,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: связь с [сервером RustDesk](https://github.com/rustdesk/rustdesk-server), ожидает удаленного прямого (через TCP hole punching) или ретранслируемого соединения
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфичный для платформы код
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для ПК-версии и мобильных устройств
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: JavaScript для Web-клиента Flutter
## Скриншоты
@@ -180,4 +179,4 @@ target/release/rustdesk

-
\ No newline at end of file
+
diff --git a/docs/README-TR.md b/docs/README-TR.md
index 99c961e8b..022335b94 100644
--- a/docs/README-TR.md
+++ b/docs/README-TR.md
@@ -166,7 +166,6 @@ Lütfen bu komutları RustDesk reposunun root klasöründe çalıştırdığın
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: [rustdesk-server](https://github.com/rustdesk/rustdesk-server) ile iletişime gir, remote direct(TCP delik açma) yada relay bağlantısı için bekle
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platforma özgü kod
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Masaüstü ve mobil için Flutter kodu
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/v1/js)**: Flutter web istemcisi için JavaScript
## Ekran Görüntüleri
diff --git a/docs/README-UA.md b/docs/README-UA.md
index eb4c9edec..12d98dbdf 100644
--- a/docs/README-UA.md
+++ b/docs/README-UA.md
@@ -59,19 +59,19 @@ RustDesk вітає внесок кожного. Ознайомтеся з [CONT
```sh
sudo apt install -y zip g++ gcc git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev \
libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake make \
- libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libpam0g-dev
+ libclang-dev ninja-build libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```
### openSUSE Tumbleweed
```sh
-sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel pam-devel
+sudo zypper install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libXfixes-devel cmake alsa-lib-devel gstreamer-devel gstreamer-plugins-base-devel xdotool-devel
```
### Fedora 28 (CentOS 8)
```sh
-sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel pam-devel
+sudo yum -y install gcc-c++ git curl wget nasm yasm gcc gtk3-devel clang libxcb-devel libxdo-devel libXfixes-devel pulseaudio-libs-devel cmake alsa-lib-devel gstreamer1-devel gstreamer1-plugins-base-devel
```
### Arch (Manjaro)
@@ -160,7 +160,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: комунікація з [rustdesk-server](https://github.com/rustdesk/rustdesk-server), очікування віддаленого прямого (обхід TCP NAT) або ретрансльованого зʼєднання
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: специфічний для платформи код
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: код Flutter для мобільних пристроїв
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript для веб клієнта на Flutter
## Знімки екрана
diff --git a/docs/README-VN.md b/docs/README-VN.md
index 38cdc10fb..34cef261f 100644
--- a/docs/README-VN.md
+++ b/docs/README-VN.md
@@ -148,7 +148,6 @@ Hãy đảm bảo rằng bạn đang chạy các lệnh này từ gốc của th
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: giao tiếp với [rustdesk-server](https://github.com/rustdesk/rustdesk-server), đợi kết nối trực tiếp (TCP hole punching) hoặc kết nối được chuyển tiếp.
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: mã nguồn riêng cho mỗi nền tảng
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Mã Flutter dành máy tính và điện thoại
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Mã JavaScript dành cho giao diện trên web bằng Flutter
## Snapshot
diff --git a/docs/README-ZH.md b/docs/README-ZH.md
index 9328e52e9..dc73d85a5 100644
--- a/docs/README-ZH.md
+++ b/docs/README-ZH.md
@@ -220,7 +220,6 @@ target/release/rustdesk
- **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: 与[rustdesk-server](https://github.com/rustdesk/rustdesk-server)保持UDP通讯, 等待远程连接(通过打洞直连或者中继)
- **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: 平台服务相关代码
- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: 适用于桌面和移动设备的 Flutter 代码
-- **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: Flutter Web版本中的Javascript代码
## 截图
diff --git a/flatpak/rustdesk.json b/flatpak/rustdesk.json
index 2418ac2a6..108a4ba1d 100644
--- a/flatpak/rustdesk.json
+++ b/flatpak/rustdesk.json
@@ -21,18 +21,6 @@
}
]
},
- {
- "name": "pam",
- "buildsystem": "autotools",
- "config-opts": ["--disable-selinux"],
- "sources": [
- {
- "type": "archive",
- "url": "https://github.com/linux-pam/linux-pam/releases/download/v1.3.1/Linux-PAM-1.3.1.tar.xz",
- "sha256": "eff47a4ecd833fbf18de9686632a70ee8d0794b79aecb217ebd0ce11db4cd0db"
- }
- ]
- },
{
"name": "rustdesk",
"buildsystem": "simple",
@@ -63,4 +51,4 @@
"--socket=pulseaudio",
"--talk-name=org.freedesktop.Flatpak"
]
-}
\ No newline at end of file
+}
diff --git a/flutter/android/app/build.gradle b/flutter/android/app/build.gradle
index 830cbc2dd..44eb32ca0 100644
--- a/flutter/android/app/build.gradle
+++ b/flutter/android/app/build.gradle
@@ -82,7 +82,8 @@ protobuf {
}
android {
- compileSdkVersion 34
+ namespace "com.carriez.flutter_hbb"
+ compileSdkVersion 36
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -91,6 +92,7 @@ android {
}
compileOptions {
+ coreLibraryDesugaringEnabled true
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
@@ -99,7 +101,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.carriez.flutter_hbb"
minSdkVersion 22
- targetSdkVersion 33
+ targetSdkVersion 36
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
@@ -128,6 +130,7 @@ flutter {
}
dependencies {
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
implementation 'com.google.protobuf:protobuf-javalite:3.20.1'
implementation "androidx.media:media:1.6.0"
implementation 'com.github.getActivity:XXPermissions:18.5'
diff --git a/flutter/android/app/src/main/AndroidManifest.xml b/flutter/android/app/src/main/AndroidManifest.xml
index f4788af4c..e07881846 100644
--- a/flutter/android/app/src/main/AndroidManifest.xml
+++ b/flutter/android/app/src/main/AndroidManifest.xml
@@ -1,15 +1,19 @@
-
+
+
+
-
-
+
+
+
@@ -26,7 +30,6 @@
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="RustDesk"
- android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true">
@@ -88,7 +91,12 @@
+ android:exported="false"
+ android:foregroundServiceType="specialUse|mediaProjection|microphone">
+
+
Boolean, private var isAudioStart: ()->Boolean) {
- private val logTag = "LOG_AUDIO_RECORD_HANDLE"
+ companion object {
+ private const val LOG_TAG = "LOG_AUDIO_RECORD_HANDLE"
+ private const val NO_ACTIVE_PUBLISHERS = 0
+ private var activeAudioFramePublishers = NO_ACTIVE_PUBLISHERS
+
+ @Synchronized
+ private fun acquireAudioFramePublisher() {
+ if (activeAudioFramePublishers == NO_ACTIVE_PUBLISHERS) {
+ FFI.setFrameRawEnable("audio", true)
+ }
+ activeAudioFramePublishers++
+ }
+
+ @Synchronized
+ private fun releaseAudioFramePublisher() {
+ if (activeAudioFramePublishers == NO_ACTIVE_PUBLISHERS) {
+ Log.e(LOG_TAG, "No active audio frame publisher to release")
+ return
+ }
+ activeAudioFramePublishers--
+ if (activeAudioFramePublishers == NO_ACTIVE_PUBLISHERS) {
+ FFI.setFrameRawEnable("audio", false)
+ }
+ }
+ }
+
+ private val logTag = LOG_TAG
private var audioRecorder: AudioRecord? = null
private var audioReader: AudioReader? = null
@@ -79,48 +105,94 @@ class AudioRecordHandle(private var context: Context, private var isVideoStart:
return
}
// read f32 to byte , length * 4
- minBufferSize = 2 * 4 * AudioRecord.getMinBufferSize(
+ val bufferSize = 2 * 4 * AudioRecord.getMinBufferSize(
AUDIO_SAMPLE_RATE,
AUDIO_CHANNEL_MASK,
AUDIO_ENCODING
)
- if (minBufferSize == 0) {
+ if (bufferSize <= 0) {
Log.d(logTag, "get min buffer size fail!")
return
}
- audioReader = AudioReader(minBufferSize, 4)
+ audioReader = AudioReader(bufferSize, 4)
+ minBufferSize = bufferSize
Log.d(logTag, "init audioData len:$minBufferSize")
}
- @RequiresApi(Build.VERSION_CODES.M)
- fun startAudioRecorder() {
- checkAudioReader()
- if (audioReader != null && audioRecorder != null && minBufferSize != 0) {
- try {
- FFI.setFrameRawEnable("audio", true)
- audioRecorder!!.startRecording()
- audioRecordStat = true
- audioThread = thread {
- while (audioRecordStat) {
- audioReader!!.readSync(audioRecorder!!)?.let {
- FFI.onAudioFrameUpdate(it)
- }
- }
- // let's release here rather than onDestroy to avoid threading issue
- audioRecorder?.release()
- audioRecorder = null
- minBufferSize = 0
- FFI.setFrameRawEnable("audio", false)
- Log.d(logTag, "Exit audio thread")
- }
- } catch (e: Exception) {
- Log.d(logTag, "startAudioRecorder fail:$e")
+ private fun releaseRecorder(recorder: AudioRecord) {
+ try {
+ recorder.release()
+ } finally {
+ if (audioRecorder === recorder) {
+ audioRecorder = null
}
- } else {
- Log.d(logTag, "startAudioRecorder fail")
}
}
+ private fun captureAudio(reader: AudioReader, recorder: AudioRecord) {
+ try {
+ while (audioRecordStat) {
+ reader.readSync(recorder)?.let {
+ FFI.onAudioFrameUpdate(it)
+ }
+ }
+ } finally {
+ minBufferSize = 0
+ try {
+ releaseRecorder(recorder)
+ } finally {
+ releaseAudioFramePublisher()
+ Log.d(logTag, "Exit audio thread")
+ }
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.M)
+ fun startAudioRecorder(): Boolean {
+ val recorder = audioRecorder
+ if (recorder == null) {
+ Log.d(logTag, "startAudioRecorder fail")
+ return false
+ }
+ var audioFramePublisherAcquired = false
+ return try {
+ checkAudioReader()
+ val reader = audioReader
+ if (reader == null || minBufferSize == 0) {
+ releaseRecorder(recorder)
+ Log.d(logTag, "startAudioRecorder fail")
+ return false
+ }
+ recorder.startRecording()
+ if (recorder.recordingState != AudioRecord.RECORDSTATE_RECORDING) {
+ throw IllegalStateException("AudioRecord failed to enter recording state")
+ }
+ audioRecordStat = true
+ val captureThread = thread(start = false) { captureAudio(reader, recorder) }
+ acquireAudioFramePublisher()
+ audioFramePublisherAcquired = true
+ audioThread = captureThread
+ captureThread.start()
+ true
+ } catch (error: Exception) {
+ audioRecordStat = false
+ audioThread = null
+ Log.e(logTag, "startAudioRecorder fail", error)
+ try {
+ releaseRecorder(recorder)
+ } finally {
+ if (audioFramePublisherAcquired) {
+ releaseAudioFramePublisher()
+ }
+ }
+ false
+ }
+ }
+
+ fun isVoiceCallActive(): Boolean {
+ return audioRecorder?.audioSource == MediaRecorder.AudioSource.VOICE_COMMUNICATION
+ }
+
fun onVoiceCallStarted(mediaProjection: MediaProjection?): Boolean {
if (!isSupportVoiceCall()) {
return false
@@ -137,11 +209,9 @@ class AudioRecordHandle(private var context: Context, private var isVideoStart:
if (!isSupportVoiceCall()) {
return true
}
- if (isVideoStart()) {
- switchOutVoiceCall(mediaProjection)
- }
+ val switched = !isVideoStart() || switchOutVoiceCall(mediaProjection)
tryReleaseAudio()
- return true
+ return switched
}
@RequiresApi(Build.VERSION_CODES.M)
@@ -159,8 +229,7 @@ class AudioRecordHandle(private var context: Context, private var isVideoStart:
Log.e(logTag, "createAudioRecorder fail")
return false
}
- startAudioRecorder()
- return true
+ return startAudioRecorder()
}
@RequiresApi(Build.VERSION_CODES.M)
@@ -177,8 +246,7 @@ class AudioRecordHandle(private var context: Context, private var isVideoStart:
Log.e(logTag, "createAudioRecorder fail")
return false
}
- startAudioRecorder()
- return true
+ return startAudioRecorder()
}
fun tryReleaseAudio() {
diff --git a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt
index 7274085fd..02cec3c25 100644
--- a/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt
+++ b/flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt
@@ -9,6 +9,7 @@ package com.carriez.flutter_hbb
import ffi.FFI
+import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
@@ -24,6 +25,10 @@ import android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
import android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
import android.media.MediaCodecList
import android.media.MediaFormat
+import android.net.Uri
+import android.provider.DocumentsContract
+import android.provider.OpenableColumns
+import android.webkit.MimeTypeMap
import android.util.DisplayMetrics
import androidx.annotation.RequiresApi
import org.json.JSONArray
@@ -33,6 +38,9 @@ import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import kotlin.concurrent.thread
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
class MainActivity : FlutterActivity() {
@@ -46,6 +54,23 @@ class MainActivity : FlutterActivity() {
private val channelTag = "mChannel"
private val logTag = "mMainActivity"
private var mainService: MainService? = null
+ private sealed class PendingPicker {
+ data class ImportFiles(val result: MethodChannel.Result) : PendingPicker()
+ data class ExportFile(val source: File, val result: MethodChannel.Result) : PendingPicker()
+ data class ImportDirectory(val result: MethodChannel.Result) : PendingPicker()
+ data class ExportFiles(
+ val sources: List,
+ val rejected: Int,
+ val result: MethodChannel.Result
+ ) : PendingPicker()
+ }
+
+ private data class ExportSource(
+ val file: File,
+ val children: List?
+ )
+
+ private var pendingPicker: PendingPicker? = null
private var isAudioStart = false
private val audioRecordHandle = AudioRecordHandle(this, { false }, { isAudioStart })
@@ -91,6 +116,108 @@ class MainActivity : FlutterActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode == REQ_IMPORT_FILES) {
+ val pending = pendingPicker as? PendingPicker.ImportFiles ?: return
+ pendingPicker = null
+ if (resultCode != Activity.RESULT_OK || data == null) {
+ pending.result.success(emptyList