[Linux/rust] Implemented high-res microphone support#655
Conversation
Adds AAC-ELD decoding using ffmpegs libavcodec and pipes the decoded 0x58 AACP stream into a virtual PipeWire input.
The capture stream and decoder thread are now started or stopped automatically based on whether an application is actively recording from the persistent virtual input device.
Introduce a centralized AppSettings struct to handle loading and saving of application configuration.
The main change is a watchdog pattern that handles missing SDUs by restarting the capture after N SDUs got lost.
corrupt connection. Exiting using the tray did not teardown the mic stream, leaving the connection in a corrupted state.
|
Two things:
|
Add a setting to automatically disable conversation detection when the Hi-Res microphone is capturing, restoring the previous state after capture ends.
capture. Disabling the high-res mic during capture removed the input device, making pipewire switch to the HFP mic.
Done. Your changes went missing for some reason. I used your card profile code snippet in the last commit. |
|
I’m not sure what happened, but I don’t hear any audio anymore on the hires output when the hires microphone is active. The hires microphone seems to be working though. I’ve tried various builds / commits to no avail. The issue started around the time when I put the AirPods back in their case without disconnecting them first and while hires audio was on. Rebooting and switching on and off hires mic didn’t help either. |
Do understand correctly: you can't hear any audio (e.g. playing a YouTube video), but the mic works correctly? Can you provide some more information about your environment? |
|
@LuanAdemi I'm on the latest Fedora 44 Kinoite. When I'm on Another thing I've noticed is that when I switch the playback from Below some extra info. Let me know what else you'd need. `$ pw-cli ls`
|
Oh. So you were using the sink as an audio output? This is a null sink my implementation needs to make some stuff easier. So if you had that sink selected as an output can you maybe try selecting the A2DP sink in the audio settings? The configuration should be: A2DP for the output, AirPods_HiRes_Mic for the input device. Just disregard that sink. If this was the issue, I might consider dropping that null sink since it might be confusing. |
I have two sinks available as output, the HiRes one which now I'm understanding is a null sink, and the AirPods. When selecting the AirPods, I hear both the desktop audio but also the audio from the microphones (with a slight delay). Even if one of them is a null sink, the other one shouldn't get the microphone stream added together with the normal desktop output. At least, this is how it looks like when I try it. Fedora 44 Kinoite, AirPods Pro 3, commit 1f8948d. Btw. This happens only when HiRes is enabled. Without it, the AirPods sink only streams the normal desktop output. |
Got it. I had this issue before. I will try to reproduce this on the new commits. Thank you for reporting and therefore supporting this effort 🙂. One more thing: Can you run For me the whole pipewire graph when playing a youtube video while recording with audacity looks like this: |
|
You can also try the new commit. It removes the null sink and pipes the mic stream through a named pipe directly to the virtual input. Previously I just created a null sink to pipe the raw audio PCMs into the PipeWire graph and used a virtual input that monitored that null sink and relays the audio to the input node. From what I can tell, there are only two ways your issue can happen. Either something is connecting the null sink to your bluez sink (1), or the input is piped into the output (2) (like a mic test in any video conference software does). The newest commit makes (1) impossible. |
|
Thank you, I’ll try! When it’s a file rather than a sink, can programs attach to it and read it? If the mute button doesn’t get respected along the path, it’d be an issue imo. |


Added support for Apple’s proprietary high-resolution microphone stream
A huge thank you to everyone in the reverse-engineering Discord channel who helped make this possible. Special thanks to @kavishdevar for the initial discovery, Bluetooth packet captures, and for figuring out the correct AACP command sequence.
How it works
AirPods are capable of transmitting a high-resolution mono microphone stream using Apple’s AACP protocol, while simultaneously maintaining high-quality audio playback over A2DP.
This pull request adds support for:
libavcodec(LGPL-licensed)TODO
AI usage
The code in this pull request was refactored using Claude Code since I have little experience with rust and my rust code sucks. I carefully reviewed and tested every ai generated code snipped.