No description
  • Rust 96.5%
  • Nix 3.5%
Find a file
2026-10-29 21:48:13 +00:00
src fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00
.gitignore fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00
Cargo.lock fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00
Cargo.toml fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00
flake.lock feat(clickshare): initial Rust crate + nix flake for ClickShare HID interface 2026-10-29 16:38:46 +00:00
flake.nix fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00
README.md fix(wayland): keep pw stream alive across main loop, deliver fresh frames, RT-safe handoff 2026-10-29 21:48:13 +00:00

clickshare

Linux userspace interface to Barco ClickShare buttons and base units. No kernel driver required: the button's control interface is plain HID (/dev/hidraw*), and base units are found on the network.

Derived from static analysis of the Windows driver pack (BarcoClickShareDrv.sys / BarcoClickShareSvc.exe) and the ClickShare Desktop App (clickshare_native.exe) — see the analysis documents for the evidence base.

Layout

  • src/device.rs — sysfs discovery of 0600:009f/00ce/0185 buttons
  • src/transport.rs — hidraw transport over hidapi
  • src/protocol.rs — bg4ctl-style framing: typed key-value payloads, get/set/notification semantics
  • src/discovery.rs — base-unit discovery: mDNS (_mirrorop2s._tcp.local, _mirrorop2upc._tcp.local) + SSDP fallback
  • src/up.rs — Unified Protocol session (state machine + auth-handshake model, WireCodec seam for the byte format)
  • src/capture.rs — screen capture: FrameSource trait, RGBA/BGRA→I420 conversion (BGRA is what PipeWire delivers), pacing, synthetic source
  • src/wayland_capture.rs — primary capture path: xdg-desktop-portal ScreenCast + PipeWire stream (feature wayland)
  • src/audio.rs — audio: AudioSource trait, ring buffer, silence detection, silence test source
  • src/hotplug.rs — button hotplug watcher + udev rule text
  • src/bin/clickshare.rs — CLI

Usage

nix run . -- list                 # buttons attached via USB
nix run . -- watch               # hotplug events (or: watch /dev/hidraw0)
nix run . -- info /dev/hidraw0    # button properties
nix run . -- led /dev/hidraw0 00ff00
nix run . -- discover             # base units on the network
nix run . -- udev-rule            # print the udev rule for hidraw access
nix run .#clickshare-wayland -- capture-test  # portal capture (Wayland)

Dev shell: nix develop. Checks: nix flake check (build, clippy, tests, fmt).

Status — read this before expecting it to work

Two layers of wire protocol are reconstructed from binaries, not yet from traffic:

  • Button protocol (protocol.rs): report IDs, property IDs and value encodings are modelled on the bg4ctl symbol families; they must be validated against a live capture before the info/led/watch commands do anything real.
  • Unified Protocol (up.rs): the session state machine and auth-handshake model are complete and unit-tested, but the byte codec (WireCodec) is deliberately unimplemented until a Wireshark capture of an app↔base-unit session exists (TLS: capture with a keylog). clickshare share is therefore an honest dry run: it verifies TCP reachability, drives the full state machine, and clearly reports that nothing was shared.

Real capture/encode plugs into the FrameSource/AudioSource traits: Wayland is the primary target (wayland_capture.rs, feature wayland, nix package clickshare-wayland), with the portal's user-consent dialog; the encoder seam (VideoFrame → MediaFrame) lands together with the wire codec.

Capturing the ClickShare wire protocols (Linux-first)

USBPcap on Windows is a last resort. In preference order:

  1. Button HID: modprobe usbmon + Wireshark on the usbmon interface while the official app talks to a plugged-in button — same data, Linux-native.
  2. Windows app without Windows hardware: QEMU/KVM with USB passthrough of the button, usbmon on the host.
  3. App ↔ base-unit TCP/TLS: Wireshark on the Linux host running the app (or in the VM); TLS needs a keylog — capture as the app's traffic only if key material is extractable, otherwise this remains the blocker it already was.

Access to /dev/hidraw* needs the udev rule (clickshare udev-rule prints it — uaccess for the logged-in user) or root.