Files
punktfunk/design/dualsense-haptics.md
T
enricobuehler 7b99b41ede docs(design): trim shipped plans, consolidate cluster, add index
Much of design/ described work that has since shipped. Trim each doc to
its durable rationale + still-open items (the code is the source of truth
for shipped detail; git history holds the full originals).

- Shipped plans -> status stubs: stats-capture, gamestream-host-plan,
  apple-stage2-presenter, windows-service.
- Trimmed completed-out / open-kept: implementation-plan, hdr-pipeline,
  host-latency, gpu-contention (fixed stale status table), game-library,
  linux-setup (fixed m0->spike + stale zero-copy claim),
  session-aware-host-followups, windows-client-bootstrap,
  windows-dualsense-{scoping,game-detection}, windows-virtual-display,
  security-review (per-finding status table; #12 still open),
  apollo-comparison (shipped backlog collapsed to one-liners).
- Windows-host cluster consolidated: windows-host.md -> redirect into
  windows-host-rewrite.md (whose stale scorecard is corrected -- goal1 is
  merged, M4 done); windows-secure-desktop.md archived (now a fallback
  behind IDD-push primary).
- Kept evergreen: ci.md, gamescope-multiuser.md, windows-build-and-packaging.md.
- New design/README.md: per-doc status table + consolidated open-items
  roll-up so nothing is tracked in only one buried doc.
- Repoint 5 code comments to the archived secure-desktop doc path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:39:06 +00:00

5.9 KiB
Raw Blame History

title, description
title description
DualSense Haptics Feasibility and scoping for audio-driven DualSense haptics.

Status: Audio-driven advanced (voice-coil) haptics — NO-GO, DEFERRED. The reachable HID work it scoped instead — adaptive triggers + two-motor rumbleSHIPPED (commit 59edeed; see CLAUDE.md gamepad section, inject/dualsense.rs). This doc is trimmed to the deferral rationale (the three walls) + the conditions that would trigger a revisit.

Advanced voice-coil haptics on the DualSense are driven by the controller's USB audio interface (4-channel surround, the back two channels carry the haptic waveform), not by HID reports. Emulating that on a Linux host and faithfully replaying it on the Apple client both hit hard walls, and the supply of software that actually emits these haptics on a Linux host is essentially zero. We defer the audio-haptics feature.

(Grounded in a 4-agent feasibility read — host USB-gadget viability, DualSense audio descriptors, Linux game demand, Apple client render path — 2026-06-10.)

The one distinction that decides everything

Feature How it's driven Reachable for us?
Basic rumble (2 motors) HID output report 0x02, bytes 34 Yes — already parsed; client already has nextRumble()
Adaptive triggers (L2/R2 resistance) HID output report 0x02, bytes 1122 / 2233 Yes — already parsed in dualsense.rs; just needs the 0xCD back-channel + client render
Advanced haptics (voice-coil actuators) USB audio interface — 4-ch, back 2 channels = haptic PCM No (for now) — see the three walls below

The UHID DualSense we already built is HID-only. It cannot present the DualSense's audio interface, so it structurally cannot carry advanced haptics. That's not a bug in our implementation — it's the wrong transport for this signal.

The three walls (any one is fatal on its own)

Wall 1 — Host capture needs a kernel rebuild

To capture haptic audio a game emits, the host must present a virtual device that owns the DualSense audio interface. The standard way is a composite USB gadget (configfs + f_hid + f_uac2) bound to a software UDC (dummy_hcd).

  • Present & enabled on this box: CONFIG_USB_CONFIGFS, CONFIG_USB_CONFIGFS_F_HID, CONFIG_USB_CONFIGFS_F_UAC2, plus libcomposite/usb_f_hid/usb_f_uac2/u_audio modules.
  • Blocker: # CONFIG_USB_DUMMY_HCD is not set in /boot/config-7.0.0-22-generic. No dummy_hcd.ko, no /sys/class/udc/. No UDC → nothing to bind the gadget to. Requires a custom kernel build to enable CONFIG_USB_DUMMY_HCD=m, plus root for module-load/configfs.

A lighter alternative exists — a virtual PipeWire/ALSA sink renamed as the DualSense (this is how the working Linux setups capture the back-2-channels today, via WirePlumber rules). It skips the kernel rebuild, but is gated by the same Wall 2 below, and games' audio-device detection is hardcoded per-title so it's fragile.

Wall 2 — Almost nothing on a Linux host emits these haptics

This is the decisive one. The supply that would feed our capture barely exists:

  • Steam Input (Linux): no official advanced-haptics support (open feature request as of 2026).
  • Sony's hid-playstation kernel driver: explicitly does not expose VCM haptics or adaptive triggers — basic rumble only.
  • RPCS3: treats the DualSense as a generic pad; no advanced haptics.
  • Native Linux games: effectively zero with advanced haptics.
  • The only working path is a handful of Proton titles (FF7 Remake, Ghostwire, Deathloop, Animal Well, Stellar Blade) via ClearlyClaire's custom Wine patches, USB-only, Steam Input disabled, forced into a 4.0-surround profile, device renamed to match Windows. ~510 games total.
  • Bluetooth can't carry it on Linux or Windows (Sony's proprietary A2DP repurposing isn't exposed).

A host-side capture feature is only as useful as the software willing to drive it. On Linux that set is a niche-of-a-niche.

Wall 3 — The Apple client can't faithfully replay it

Even with a captured waveform, the primary client (macOS/iOS) can't render it well:

  • macOS GameController exposes the DualSense as a basic gamepad — no voice-coil / adaptive-trigger access. Those are PS5-only in Apple's stack.
  • CoreHaptics is discrete, pattern-based (CHHapticPattern events, ≤30 s), not a PCM streaming sink. Converting a streamed haptic waveform to patterns is lossy — it throws away exactly the fidelity that makes voice-coil haptics worth having.
  • There is no public macOS API to route CoreAudio to the DualSense's channels 34. Doing it anyway means private/reverse-engineered APIs that break across OS updates.

Conditions for a future GO on audio haptics

Revisit if all three change:

  • A real DualSense is available on the dev box to capture an authoritative lsusb -v + the exact UAC channel/sample-rate/format layout (today: undocumented, would need reverse-engineering).
  • The host target gains a UDC (custom kernel with dummy_hcd, or real hardware OTG) or we accept the PipeWire-renamed-sink path and the title set that emits haptics on Linux grows beyond the Proton-patch niche.
  • The client target shifts to one that can render PCM haptics (a Linux/Windows client with direct CoreAudio-style channel access, or a future Apple API) — or we accept lossy pattern conversion.

Until then the cost/benefit is upside-down: three hard subsystems (kernel, USB gadget, audio routing) to serve ~510 Proton titles, rendered lossily on the one client we ship.

Open items

  • Audio-driven advanced (voice-coil) haptics — DEFERRED. Explicitly blocked until all three "Conditions for a future GO" above are met (a real DualSense to capture the UAC layout, a host UDC or grown Linux haptic-title supply, and a client that can render PCM haptics). This doc is the down payment to revisit then.