Most plausible explanation for the negative-evidence pattern (kernel
gave up, public RE blocked, our matching every documented "enable" bit
got nothing back): the DS5 ↔ PS5 mic channel is encrypted with a
session key derived during pairing, on a Sony-proprietary L2CAP PSM.
Sony's incentives all align with this — voice chat data from a $40
third-party dongle routed to an attacker is a worst-case PR / GDPR
scenario, and anti-spoofing is its own threat model.
Mechanism that fits: BT-Classic SSP link key → Sony-proprietary KDF →
audio-channel session key (likely AES-CCM). PS5 firmware on both ends
knows the KDF; third parties don't. Even a BT sniffer would see only
encrypted payload blobs without the KDF.
Re-frames "we can't get mic over BT" from "we haven't tried hard
enough" to "the architecture is intentionally hardened" — a clear
answer to give users + a clear bar for anyone wanting to actually
pursue this.
Credit: hypothesis suggested by MarcelineVPQ ("its probably encrypted,
I think the microphone over bluetooth is a security concern for sony").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.4 KiB
Bluetooth microphone investigation — current status
TL;DR: The DualSense's built-in microphone does not work when the controller is paired to this dongle over Bluetooth. It works fine when the controller is connected directly to a host over USB. This is a Sony / DS5-firmware-side limitation we currently can't work around without reverse engineering or BT-sniffer access to PS5 ↔ DS5 traffic. The same limitation is documented in the upstream Linux kernel driver (drivers/hid/hid-playstation.c line ~1509: "Bluetooth audio is currently not supported").
This file is a hand-off / research log for the next person who tries.
What does work
- Direct USB-C from DS5 → host: mic enumerates as a UAC1 IN endpoint at 48 kHz / 16-bit / 2 channels on
EP 0x82, max packet 196 bytes. ALSA recognizes it ascard N: Controller [DualSense Wireless Controller].arecordcaptures real audio after raising theHeadset Capture Volumemixer control (it defaults to 0 dB). - Our dongle's USB descriptor correctly mirrors the DS5's UAC1 layout — same interfaces, same alt settings, same endpoint addresses, same packet sizes. Verified with
lsusb -vagainst a real DS5. - All the firmware-side decode infrastructure for BT mic is in place (Opus decoder,
mic_fifoqueue,tud_audio_writeto the IN endpoint, mono → stereo duplication) — seesrc/audio.cpp. It's currently gated behindif (false)insrc/main.cpp'son_bt_data()because we have nothing to feed it.
What doesn't, and why
The DS5 firmware on the test controller (build date Jul 4 2025, queried via feature report 0x20) does not stream microphone audio over the standard BT-HID L2CAP channels (PSM 0x11 control + 0x13 interrupt).
What we tried:
- Upstream
awalol/DS5Donglemicbranch as reference. That branch claims to extract a 71-byte Opus packet atdata + 4of any BT input report where(data[2] >> 1) & 1is set. On our DS5 firmware, bit 1 of byte 2 is never set (verified across thousands of frames via theg_31_b2_orOR mask). The upstream RE was likely done on a different (older) DS5 firmware revision. - Bit 0 of byte 2 matches roughly all standard input reports — confirmed by reading the supposed "mic prefix" via
0xFDfeature report and seeing live stick X/Y values (not Opus data). Not a mic flag. - Frame length sweep. Longest BT 0x31 frame we ever see is 79 bytes — a fully-decoded standard DS5 input report (sticks + IMU + touchpad + battery + sensor timestamp + trailing zeros). No audio bytes appended anywhere.
- Other report IDs. Counted ALL incoming BT input reports by report ID. Only
0x01(rare) and0x31(common). No 0x33 / 0x35 / 0x36 / 0x39 / etc. The DS5 isn't sending anything mic-shaped on a different ID. - State configuration matching the kernel. Set
AllowAudioControl=1,AllowMicVolume=1,AllowAudioMute=1,MicSelect=Internal,VolumeMic=0x40,MicMute=0,AudioPowerSave=0— exactly whathid-playstation.csets when calling its "Enable microphone" path. DS5 still doesn't stream. - Bidirectional audio session hypothesis. Maybe the DS5 only streams mic when there's also active speaker audio (
0x36packets) flowing. Tested: ranaplay /dev/zerosimultaneously witharecord. No change in BT-side counters, no new report IDs, no longer frames. Disproved. - State refresh on host UAC1 alt-setting change. Considered hooking
tud_audio_set_itf_cb(itf=2, alt=1)to send the DS5 a fresh "enable mic" state update. Not implemented — given the kernel comment and our state matching the kernel's own "enable" sequence, this wouldn't have helped.
What we did not try (real next steps if anyone picks this up):
- SDP browse the DS5 over BT after pairing. Discover what L2CAP PSMs / services it advertises beyond HID. If there's a Sony proprietary audio PSM we haven't subscribed to, that's where mic traffic might live.
- Open additional L2CAP channels (proprietary audio PSM if found, or standard ones like A2DP=0x19 / RFCOMM=0x03) and watch for unsolicited inbound data.
- Compare DS5 firmware revisions. Test with an older DS5 (pre-2024 manufacture) and see if it streams mic over BT — that would tell us whether Sony removed the feature or just nobody documented the protocol. (We only have one DS5; can't test.)
- BT sniffer between a PS5 console and a DS5 during voice chat. Tells us exactly what L2CAP channels and bytes Sony uses for mic. Equipment-intensive (~$50–200 for an Ubertooth or commercial sniffer).
- DS5 firmware disassembly. Legally fraught, almost certainly EULA-violating.
Strongest hypothesis: the channel is encrypted
The shape of all the negative evidence — kernel maintainers giving up, no public RE project succeeding, our matching every documented "enable" bit and getting nothing — strongly suggests the channel is encrypted with a session key derived during pairing, not just transported on an undocumented PSM. Sony's incentives line up perfectly:
- PR / privacy: a $40 third-party dongle routing a user's PS5 voice chat to a malicious host is a worst-case PR scenario. Encrypting the mic channel is the obvious defense.
- GDPR-class regulation: voice biometrics from a console controller over plaintext BT is the kind of thing EU regulators ask hard questions about.
- Anti-spoofing: prevents injecting fake mic data into a PS5 session, which is its own threat model.
Mechanism that fits the evidence:
- During pairing, BT Classic SSP produces a link key. The PS5 + DS5 firmware likely run a Sony-proprietary KDF on top of that link key to produce an audio-channel session key.
- Mic audio is transported on a Sony-allocated proprietary L2CAP PSM (not in the standard BT-SIG ranges) and encrypted with that session key (AES-CCM or similar).
- A third-party dongle could connect to the PSM if it knew the number, but without the KDF / session key the payload would be opaque encrypted blobs.
Implication: a BT sniffer might tell us the PSM and packet timing/sizes, but not the payload contents. Building a PS5-impersonating dongle that derives valid session keys would require either Sony system-software disassembly or DS5 firmware disassembly — legally fraught, and a much bigger undertaking than what this project is set up for.
This re-frames "we can't get mic over BT" from "we haven't tried hard enough" to "the architecture is intentionally hardened against exactly this." That's not nothing — it's a clear answer to give users who ask, and a clear bar to clear if anyone wants to actually pursue it.
What we built that's useful regardless
These all stay shipped — they're general-purpose audio-debug infrastructure now:
scripts/mic_diag.shwith subcommandsstatus,capture [secs],watch,bt-trace. Drives the entire diagnostic loop from the host without needing OLED-relay-through-the-user; reads vendor feature reports via/dev/hidraw.- Vendor HID feature report
0xFD(32 bytes): BT input-report counter, non-0x31 counter, last seen non-0x31 report ID, OR mask of byte 2 across 0x31 frames, length range, hex prefix of last frame. - Vendor HID feature report
0xFE(82 bytes): full content of the longest 0x31 frame seen, for byte-level inspection. - OLED Diagnostics screen carries BT31/Mic rate + recent frame prefix + opus dec/wrote bytes — useful for any future audio-path debugging at the bench.
src/audio.cppmic-decode infrastructure (Opus decoder on core0, FIFO, mono → stereo duplication,tud_audio_writeto IN endpoint). Disabled at themic_add_queuecall site, ready to re-enable the moment a real mic trigger is identified.src/state_mgr.cppinitial state corrected —VolumeMicwas0xff(out of valid range per spec; max is0x40),MuteControlhad all*PowerSavebits set which would have power-gated the audio DSP. These corrections don't enable BT mic but they're the right defaults regardless.
References
- Linux kernel
drivers/hid/hid-playstation.c. Quoted lines: ~1407–1420 (mic enable/disable), ~1509 ("Bluetooth audio is currently not supported"). Raw source on GitHub mirror. - PSDevWiki DualSense HID Commands — has factory/manufacturer commands (report IDs 128, 129, 160, 164, 165) for BT patches and audio codec selection, but explicitly notes most "do not work with retail controllers". Not a path forward.
- Upstream
awalol/DS5Donglebranchmic(commits9c197fc feat: mic work,3829163 mic mono channel). RE'd a working mic path for an older DS5 firmware revision; we ported the data plumbing but the BT-side trigger differs on current firmware. - dualsensectl:
command_microphone on/offsetsvalid_flag0 |= DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLEand clearsDS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE. Same as what we already do on connect.
For users asking about the mic
When users report "the mic doesn't work":
- Plug the DS5 into the host via USB. Mic works out of the box. You may need to raise the
Headset Capture Volumemixer control if it defaults to 0 dB. - Over the dongle's Bluetooth pairing, the mic is currently a known limitation — not something a firmware update on our side can fix without further reverse engineering of the DS5's proprietary BT audio path.
- The diagnostic tools in
scripts/mic_diag.share available if you want to help reverse engineer this; PRs welcome.