* feat(recording): add visibility and service storage options
- support hide-recording-button in Flutter and Sciter
- allow a custom save directory for Windows service recordings
- sanitize peer IDs used in recording filenames
Tested:
- with hide-recording-button=Y and allow-auto-record-outgoing=Y,
outgoing sessions are recorded automatically while the recording button
remains hidden and cannot be stopped from the UI; verified on Flutter
desktop, Sciter, and Android
- windows-service-video-save-directory takes effect when the Windows client
runs as an installed service
- the Windows controlling side can save recordings for direct IP:port
connections
Signed-off-by: 21pages <sunboeasy@gmail.com>
* update hbb_common
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(recording): validate configured save directories
- trim configured recording directory paths
- reject non-absolute paths and fall back to defaults
- warn when a non-empty path is invalid
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix(recording): validate configured save directories
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>
* fix: refresh wayland uinput range on compositor layout change
The uinput absolute range is computed once at session init. If the
compositor layout changes mid-session (monitor scale or position
change, or a portal virtual output appearing once capture starts),
injected coordinates are rescaled by the stale range and land offset.
Poll the live desktop bounding box from the display service loop while
subscribed (one wayland roundtrip, throttled to 1.5s, no subprocesses)
and re-apply the uinput resolution when it changes. Also read a fresh
layout when computing the initial range in check_init, since the cache
is not cleared when a session closes through the restore-token path.
This is the X component of #15601. The stale advertised origins (the Y
component) are not touched here: re-advertising DisplayInfo mid-session
trips the portal re-negotiation and can drop displays.
Signed-off-by: Cody Harris <codyharris7188@gmail.com>
* fix: bound the mouse resolution IPC wait during session init
Wrap update_mouse_resolution in the same 3s timeout the periodic
refresh uses, so a hung IPC response can't stall check_init.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: build timeout future inside runtime, split linux lazy_static
Constructing the timeout future eagerly as the block_on argument panics
with 'there is no reactor running'; move it into the async block so it is
built inside the runtime context. Also move WAYLAND_UINPUT_RECT into its
own cfg-gated lazy_static block, an attribute on a single item inside the
shared block does not compile.
* fix: confirm uinput mouse device adopted new range before caching rect
send_refresh() now waits for the mouse service to ack that it recreated the
device with the new range instead of firing and forgetting, and
update_mouse_resolution() propagates that result. The layout poller only
caches the rect after the device actually adopts the range, so a failed
refresh errors and retries on the next check. The ack read is bounded by
IPC_REQUEST_TIMEOUT, matching the keyboard get-key-state path.
* fix: propagate refresh failures instead of caching a stale range
- input_service: error when the custom-mouse downcast fails so the poller
retries instead of caching an unconfirmed refresh
- uinput: on device recreation failure, keep the current device and the
IPC connection and withhold the ack so the client retries, instead of
killing the mouse handler
* fix: remap injected wayland coords onto the live layout after a monitor moves
The range refresh corrects the uinput ABS bounds, but a single-display client
sends whole-desktop coordinates offset by the origin of the display it follows,
taken from the layout advertised at session init. When another monitor is
rescaled or moved that origin shifts, so the coordinate lands offset before it
reaches uinput and the range refresh cannot recover it.
Snapshot the per-display layout at init, poll the live layout on the existing
1.5s throttle, and when they differ remap each injected move into the followed
display's current rectangle (matched by connector name, index fallback when the
compositor reports none). No-op and lock-free while the layout is unchanged.
---------
Signed-off-by: Cody Harris <codyharris7188@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
bindgen-0.65 is incompatible with llvm 22, we should upgrade to a
newer bindgen version
error message:
```
error[E0609]: no field `g_w` on type `vpx_codec_enc_cfg`
--> libs/scrap/src/common/vpxcodec.rs:66:19
|
66 | c.g_w = config.width;
| ^^^ unknown field
|
= note: available field is: `_address`
```
* Add initial arm64 build logic
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Upgrade Flutter to 3.44.0 and introduce Windows arm64 in CI
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Bump bridge build to Flutter 3.44 as well
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Fix install flutter step for Win arm64
* Bump install-llvm-action to v2 for arm64 support
* Fix libsodium logic to only install through vcpkg on win arm64
* Fix Flutter installations on Win
* Flutter XCode: only build the current arch as it defaults to universal
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Ensure that we really have arm64 Dart + Flutter engine in CI
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Enable hwcodec feature now that upstream supports building it
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* CI: improve logic for getting Flutter arm64 SDK
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
* Apply PR feedback (only bump Flutter version on Win arm64)
* Exclude MSI build on arm64
* CI: build the MSI for Windows arm64 (WiX v4 ARM64 platform + native CustomActions)
* Address PR feedback
* Update Cargo.toml
* Update Cargo.lock
* Update Cargo.lock
* Add Flutter 3.44 DialogThemeData background colors
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
Signed-off-by: 21pages <sunboeasy@gmail.com>
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: 21pages <sunboeasy@gmail.com>
On Wayland compositors whose xdg-desktop-portal backend exposes screencast
frames as DMA-BUF buffers — notably xdg-desktop-portal-cosmic 0.1.0 on
Pop!_OS 24.04 / COSMIC — inbound screen capture fails. PipeWireRecorder
links pipewiresrc directly to an appsink whose caps only accept
video/x-raw BGRx/RGBx in system memory. That format set is too narrow for
the portal's buffer-type / modifier negotiation, which collapses with:
pw.link: negotiating -> error no more output formats (-22)
gstpipewiresrc: stream error: no more output formats
gstbasesrc: streaming stopped, reason not-negotiated (-4)
ERROR src/server/wayland.rs: Failed scrap Element failed to change its state
Inserting a videoconvert element between pipewiresrc and appsink widens
the negotiable format set to any system-memory video/x-raw format, giving
the portal room to settle on a format it can deliver via its SHM path.
videoconvert then converts to the BGRx/RGBx the appsink expects.
Verified on Pop!_OS 24.04 / COSMIC with gst-launch, before and after:
# fails (current behaviour):
gst-launch-1.0 pipewiresrc path=N ! video/x-raw,format=BGRx ! fakesink
# works (with this change):
gst-launch-1.0 pipewiresrc path=N ! videoconvert ! video/x-raw,format=BGRx ! fakesink
After the change, inbound connections capture and stream the desktop
normally and the "Failed scrap" error no longer occurs.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Updated build.rs to tell RustC that dxgi, quartz and x11 are expected configurations.
Added lifetime annotations to various methods in common/aom.rs and common/vpxcodec.rs.
Updated common/vpx.rs to allow unused_imports in the generated bindings.
Updated dxgi/mag.rs to allow non_snake_case identifiers like "dwFilterMode".
* Added lifetime annotations to methods in common/hwcodec.rs and common/vram.rs.
* Switched syntax for the rustc-check-cfg directive emitted by build.rs in the scrap crate to use syntax compatible with Rust toolchain version 1.75. The double-colon syntax requires 1.77 or newer, but the older single-colon syntax works fine on newer versions for this directive.
* Update libs/scrap/build.rs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Revert apparently-erroneous AI suggestion. It's usually pretty good, but not always right it seems. :-)
This reverts commit bf862b13f6.
* Removed redundant configuration directives from libs/scrap/build.rs.
---------
Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add Wayland multi-monitor screen capture functionality
* fix wayland capture issues by reverting to CapturerPtr, the problem was that calling Display::all in get_capturer_for_display was dropping the pipewire capturer and causing the video to freeze.
* If running as AppImage or flatpak, ignore the 'multiple' argument
* Comment out warning log with unclear purpose Comment out warning log with unclear purpose
---------
Co-authored-by: fufesou <13586388+fufesou@users.noreply.github.com>
* option `allow-d3d-render`, default false
Add this option because it fails on some machines
Signed-off-by: 21pages <sunboeasy@gmail.com>
* only add nokhwa to windows and linux dependencies
Signed-off-by: 21pages <sunboeasy@gmail.com>
---------
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Adjust bitrate and fps based on TestDelay messages.
* Bitrate is adjusted every 3 seconds, fps is adjusted every second and when receiving test lag.
* Latency optimized at high resolutions. However, when the network is poor, the delay when just connecting or sliding static pages is still obvious.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Fix ffmpeg videotoolbox wrong log when changing bitrate
* Let qsv support abr, and it's safe for qsv to changing bitrate.
Signed-off-by: 21pages <sunboeasy@gmail.com>
1. Dropping frames can cause this error, reset encoder when this
happens.
2. There are some logic error for clear video queue, because video queue
message is not cleared. This need to be fixed.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Rotate ID3D11Texture2D after duplication with d3d11 video processor.
* If display is not rotated, nothing will be created; If the rotation
fails, it will use the old fallback logic
TODO:
* If changing from Landscape to Landscape(flipped) during capture, the resolution is
not changed, video service fallback to gdi directly.
Signed-off-by: 21pages <sunboeasy@gmail.com>
* Add option auto record outgoing session
* In the same connection, all displays and all windows share the same
recording state.
todo:
Android check external storage permission
Known issue:
* Sciter old issue, stop the process directly without stop record, the record file can't play.
Signed-off-by: 21pages <sunboeasy@gmail.com>