Skip to content

Add DualSense Bluetooth audio and haptics streaming - #18

Open
potpiemuncher wants to merge 4 commits into
ds4windowsapp:mainfrom
potpiemuncher:feature/dualsense-bt-audio-haptics-upstream-pr
Open

Add DualSense Bluetooth audio and haptics streaming#18
potpiemuncher wants to merge 4 commits into
ds4windowsapp:mainfrom
potpiemuncher:feature/dualsense-bt-audio-haptics-upstream-pr

Conversation

@potpiemuncher

Copy link
Copy Markdown

Summary

This adds opt-in Bluetooth audio and haptics streaming for first-party DualSense controllers.

From Device Options, users can now:

  • convert a selected Windows playback stream into DualSense haptics;
  • convert DS4Windows rumble into haptic-actuator output;
  • mix audio-derived and rumble-derived haptics;
  • relay listening audio to the controller speaker or headphone jack; and
  • select Smooth, Balanced, or Low Latency buffering.

The feature is disabled by default. Listening audio defaults to 50% volume.

Implementation

The streamer uses the existing Bluetooth HID connection and sends the controller's 0x36 audio container with:

  • 3 kHz stereo haptic PCM;
  • 48 kHz stereo Opus listening audio;
  • automatic, speaker, or headphone routing;
  • serialized HID output so regular controller state and stream reports cannot overlap; and
  • bounded stream writes with request-specific cancellation and completion draining.

The existing DualSense output path continues to handle input, LEDs, and adaptive-trigger state. While advanced haptics are active, legacy rumble flags and stale motor bytes are suppressed because the controller cannot use both firmware modes simultaneously. Modes containing "Rumble To Haptics" preserve game rumble by synthesizing it into the haptic stream.

The capture path includes clock-drift correction, adaptive prebuffering, skipped late deadlines instead of catch-up bursts, decaying underrun fillers, resume fade-in, and an idle silence gate.

Settings are persisted per controller and the new UI strings are localized through the existing resource system.

Safe behavior

  • Haptics and listening audio are off by default.
  • The implementation captures an existing Windows render endpoint through WASAPI loopback.
  • It does not register a new Windows audio endpoint.
  • It does not change the Windows default playback device.
  • A missing or unsupported capture endpoint falls back to normal controller rumble rather than leaving streaming partially active.

Validation

  • Focused DualSense audio, report, lifecycle, and settings tests: 36 passed
  • Full test suite: 43 passed, 3 failed
    • The same three profile-XML snapshot failures reproduce on unmodified upstream main:
      • AppSettingsTests.CheckSettingsSave
      • ProfileMigrationTests.CheckJaysProfileRead
      • ProfileTests.CheckWriteProfile
  • Release builds completed successfully for x64 and x86
  • Hardware-tested on a first-party DualSense over Bluetooth:
    • Smooth, Balanced, and Low Latency profiles
    • clean audio with no clicks or choppiness
    • correct input, rumble-derived haptics, audio-derived haptics, routing, and silence/resume behavior
    • no observed dropped frames, slow HID writes, write failures, or default-device changes

Dependencies and attribution

This adds:

  • Concentus 2.2.2
  • NAudio.Wasapi 2.2.1, with NAudio.Core transitively

THIRD-PARTY-NOTICES.txt records the applicable licenses and acknowledgments for Concentus, NAudio/Cockos WDL, DS5Dongle AutoHaptics, and the SAxense protocol research. The notice is copied into build and publish output.

Scope

This PR contains only the standard DS4Windows Bluetooth streaming path. It does not include Native Mode, virtual USB devices, usbip-win2, kernel drivers, elevated helpers, or USB capture tooling.

Current limitations

  • Microphone transport is not implemented.
  • DualSense Edge hardware has not yet been validated.
  • Low Latency requires a sufficiently clean Bluetooth link.
  • The controller is a relay destination, not a Windows audio endpoint.

Additional protocol and implementation details are documented in doc/dev/dualsense_bluetooth_audio_haptics.md.

@potpiemuncher

Copy link
Copy Markdown
Author

Marking this ready for review — and since it is a sizeable PR for a small fork, a short note on what I am actually asking for.

What it is: opt-in Bluetooth audio and haptics for first-party DualSense controllers — audio-derived haptics, rumble-to-haptics, and listening audio to the controller speaker/headphone jack. It uses the Bluetooth HID connection that DS4Windows already owns, via the controller's 0x36 audio container.

Why I think it is safe to consider:

  • Off by default. Nothing changes for existing users who do not enable it.
  • No kernel driver, no elevation, no new Windows audio endpoint, and it does not change the default playback device — it captures an existing render endpoint through WASAPI loopback.
  • Falls back to normal rumble if the capture endpoint is missing or unsupported.
  • Self-contained: it touches the DualSense output path and adds settings/UI, rather than reworking shared plumbing.

Validation on my end: clean dotnet publish for x64 and x86 with 0 errors (the same invocation release.yml uses); 36/36 focused DualSense/haptics tests; full suite 43 passed / 3 failed, where those 3 are the pre-existing profile-XML snapshot tests (CheckSettingsSave, CheckJaysProfileRead, CheckWriteProfile) that also fail on unmodified main. Hardware-tested on a real DualSense over Bluetooth across all three latency profiles.

One CLI gotcha if you try to run the tests yourself: dotnet test on the test project fails with _wpftmp CS0246 errors because the WPF XAML markup-compile temp project does not inherit the PackageReferences. It is not a code problem and does not affect dotnet publish or release.yml. Building the app project first, then the test project with -p:BuildProjectReferences=false, then dotnet test --no-build, works.

Happy to adjust:

  • I can split this into smaller sequential PRs (settings → streamer → UI → docs) if that reviews better.
  • New UI strings are in the neutral Strings.resx only, so other languages fall back to English. Tell me if you would rather have stubs in every Strings.<lang>.resx.
  • New dependencies are Concentus (Opus) and NAudio.Wasapi, both recorded in THIRD-PARTY-NOTICES.txt along with the DS5Dongle and SAxense protocol-research acknowledgements. If either dependency is a problem, say so — that is worth knowing before you spend review time.

Explicitly not part of this PR: the experimental Native Mode work in #19 (virtual USB device, usbip-win2, elevated helper). That is a separate draft/RFC and deliberately depends on nothing here. #19 should not block this one, and I am not asking you to review it on the same timeline.

If you would rather not take a feature of this size at all, that is a completely fair answer — I would just appreciate knowing early.

@potpiemuncher
potpiemuncher marked this pull request as ready for review July 24, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants