No description
Find a file
Breadway 2cc1310752 Detect the DMA-BUF crash bug by Hyprland version, add a capture-stall watchdog
The 1080p DMA-BUF pipeline crashed the user's entire Hyprland session
tonight. Root cause identified: hyprwm/Hyprland PR #15167 (fixed
2026-06-18, first shipped v0.56.0) -- CGLRenderbuffer's destructor
unconditionally dereferences m_framebuffer, which is left null when
createEGLImage() fails to import the DMA-BUF. This machine runs
v0.55.4, a week before the fix. The crash happens inside Hyprland's
own Screenshare::CScreenshareFrame::copyDmabuf(), confirmed against
the coredump; it is not a breadcast, GStreamer, or PipeWire bug, and
it is not resolution-dependent (upstream's own reports span unrelated
triggers -- touchpad gestures, tab switching, a Discord stream -- not
capture geometry), so 1080p vs 720p was never the actual variable.

choose_capture_backend() now reads the running compositor's version
over its own IPC socket and only uses the DMA-BUF path on Hyprland
>= 0.56.0 (or non-Hyprland sessions, unaffected by this bug). Below
that, or if the version can't be determined, it falls back to the
plain system-memory/wl_shm pipeline -- slower and still subject to
xdg-desktop-portal-hyprland's separate "Out of buffers" stall bug
(also confirmed via journalctl, and also not fixed in the installed
xdpw 1.3.12), but that failure mode is a stall, not a compositor-wide
abort.

That stall used to be silent forever: xdpw stops requesting frames
after 10 failed retries and never signals PipeWire, so GStreamer's own
bus reports nothing -- no error, no EOS -- and the frame pump just
blocks. pull_encoded_frame now bails after 10s of a Playing pipeline
producing nothing, converting an indefinite silent freeze into a real,
reported session failure (still correctly distinguishing a genuine
stall from ordinary EOS/teardown, so a normal stop() doesn't trip it).

VideoParams is no longer a hand-synced constant: build_video_pipeline_for_streaming
now returns the geometry/frame-rate it actually chose alongside the
pipeline, and both breadcastd::cast_mirror and cast_stream_test thread
that straight into the OFFER instead of a separately-maintained
default. Keeping two copies in sync by hand is exactly how the
resolution mismatch bug happened earlier tonight; returning the real
value makes that class of bug unrepresentable rather than just fixed
once.

Verified without touching the real compositor: cargo build --workspace
--examples, clippy, and both new unit tests (version parsing, the
0.55.4/0.56.0 backend-selection boundary) are clean. The watchdog's
firing path and the DMA-BUF path post-Hyprland-update are not yet
validated against real hardware -- deliberately, given what the last
live test cost. Recommended order: update Hyprland
(pacman -Syu hyprland xdg-desktop-portal-hyprland gets 0.56.1 + xdpw
1.4.1, which also picks up upstream fixes for the exact copy-fence and
SHM-handling bugs hit tonight) and confirm `hyprctl version` reports
>= 0.56.0 before testing DMA-BUF again. Without updating, this commit
still helps: the wl_shm path is selected automatically and the stall
is now bounded instead of indefinite.
2026-08-15 22:34:21 +08:00
.forgejo/workflows ci: build on bread-ecosystem's shared Arch container 2026-08-05 19:16:28 +08:00
breadcast Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
breadcast-caststream-sys Measure real EnqueueFrame outcomes, then size the send window to fit RTT 2026-08-15 22:34:21 +08:00
breadcast-core Detect the DMA-BUF crash bug by Hyprland version, add a capture-stall watchdog 2026-08-15 22:34:21 +08:00
breadcastd Detect the DMA-BUF crash bug by Hyprland version, add a capture-stall watchdog 2026-08-15 22:34:21 +08:00
ci ci: build on bread-ecosystem's shared Arch container 2026-08-05 19:16:28 +08:00
contrib Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
graphify-out docs: describe the shipped bakery product and single-trunk releases 2026-08-15 21:38:38 +08:00
vendor/rust_cast-0.21.0 Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
.gitignore gitignore: ignore graphify-out/ knowledge-graph cache 2026-08-15 22:34:21 +08:00
AGENTS.md Track AGENTS.md 2026-08-15 22:03:30 +08:00
bakery.toml docs: describe the shipped bakery product and single-trunk releases 2026-08-15 21:38:38 +08:00
Cargo.lock Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
Cargo.toml Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
CONTRIBUTING.md docs: describe the shipped bakery product and single-trunk releases 2026-08-15 21:38:38 +08:00
EVENTS.md Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
LICENSE Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration 2026-08-03 09:07:21 +08:00
README.md docs: describe the shipped bakery product and single-trunk releases 2026-08-15 21:38:38 +08:00

breadcast

Cast your screen to a Chromecast, Google TV, or DLNA renderer on the LAN. Two binaries:

  • breadcastd — background daemon. Discovers Cast (mDNS) and DLNA/UPnP (SSDP) devices, owns the portal screen-capture / encode pipeline, and runs the live session: Cast Streaming (vendored openscreen) or DLNA/AVTransport. One active session at a time.
  • breadcast — GTK4 Layer Shell popup. Thin IPC client of breadcastd: pick a device, start or stop a cast. Closing the popup does not interrupt an active session.

This is a bakery product. It is not shipped on the BOS ISO and is not part of the default desktop — install it yourself if you want it.

Install

bakery install breadcast

That puts breadcast and breadcastd on $PATH (usually ~/.local/bin), installs contrib/breadcastd.service as a systemd user unit, enables it, and starts the daemon. bakery doctor breadcast checks the system packages listed in bakery.toml first.

Requirements

  • A Wayland compositor with Layer Shell and xdg-desktop-portal ScreenCast (Hyprland is the primary target)
  • GTK 4.12+ and gtk4-layer-shell
  • GStreamer plus gst-plugin-pipewire, gst-plugins-bad, gst-plugin-va (vah264enc), and gst-plugin-hlssink3
  • jsoncpp and openssl (runtime deps of the vendored Cast Streaming code)

From source you also need a Rust toolchain (edition 2021).

Build from source

git clone https://git.breadway.dev/Breadway/breadcast
cd breadcast
cargo build --release

Binaries land at target/release/breadcast and target/release/breadcastd.

cp target/release/breadcast target/release/breadcastd ~/.local/bin/
cp contrib/breadcastd.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now breadcastd

Usage

Start the daemon (or let the systemd unit handle it):

breadcastd

Open the device picker:

breadcast

Running breadcast again while it is open closes it (toggle). Click a device to start mirroring — the portal picker asks which screen to share. Stop mirroring ends the session. Status is Idle or Casting.

Discovery examples (optional, for debugging the LAN):

cargo run -p breadcast-core --example discover
cargo run -p breadcast-core --example dlna_discover

Hyprland keybind

On stock Hyprland, add the contents of contrib/hyprland.conf to your hyprland.conf if you want Super+C and the frosted-glass blur:

layerrule = blur, breadcast
layerrule = ignorezero, breadcast

bind = $mainMod, C, exec, breadcast

BOS does not ship this app or a default keybind for it. Add one yourself if you install breadcast on a BOS machine.

bread event integration

breadcastd works the same with or without breadd. When breadd is running, it publishes bread.cast.* and honors bread.command.cast.*. See EVENTS.md for the bus contract. bread is not a bakery dependency.

Theming

breadcast inherits its colour palette from bread-theme.