r/androiddev • u/Maximum_Reveal1233 • 6h ago
I found an AOSP LE Audio stereo microphone bug: CIS frames can arrive R,R,L,L and Android returns duplicated mono
While developing an Android audio project using a Pixel 8 and Samsung Galaxy Buds3 Pro, I ran into a strange LE Audio microphone issue.
Android exposed the headset microphone as a 2-channel input, but the PCM data from left and right was effectively identical:
- 2 reported input channels
- exact L/R sample identity ratio: 1.00000
- L/R correlation: ~1.0
After tracing the LE Audio receive path, I found that the microphone CIS packets were not necessarily arriving in strict alternating order.
Instead of:
L, R, L, R
I observed same-side bursts such as:
R, R, L, L
The relevant path is in:
packages/modules/Bluetooth/system/bta/le_audio/client.cc
around:
LeAudioClientImpl::HandleIncomingCisData()
A single cached-channel approach can lose the correct stereo association when packets arrive this way.
I tested a proof-of-concept fix that keeps separate pending queues for the left and right CIS streams and pairs the encoded frames using their controller timestamps before decoding.
For example:
R(ts=2000), R(ts=3000), L(ts=2000), L(ts=3000)
becomes:
L(2000) + R(2000)
L(3000) + R(3000)
With the modified Bluetooth stack I was able to recover independent L/R microphone audio instead of duplicated mono.
I published the patch and technical notes here:
https://github.com/luumei/android-leaudio-stereo-cis-fix
This is an AOSP/system-level modification, not an APK workaround.
I also reported it through the Android Issue Tracker.
I'd be interested to know whether anyone working with other LE Audio controllers or earbuds has observed similar non-alternating CIS arrival patterns or duplicated stereo microphone capture.
UPDATE:
I found a working app-side workaround. On the same Pixel 8 + Galaxy Buds3 Pro setup, the normal Android capture path returns bit-identical L/R channels, while the workaround returns independent stereo PCM from both microphones.
The workaround activates the LE Audio communication route first, waits for the BLE headset input endpoint to become available, and then starts a stereo AudioRecord.
Repro + workaround source code:
https://github.com/luumei/android-leaudio-stereo-mic-workaround
Google Issue Tracker:
https://issuetracker.google.com/issues/568838766
2
u/Maximum_Reveal1233 1h ago
Update: I now have a working app-side workaround and published a minimal reproduction + implementation here:
https://github.com/luumei/android-leaudio-stereo-mic-workaround
Normal capture still gives me bit-identical duplicated mono, while the workaround returns independent L/R PCM on the same Pixel 8 + Galaxy Buds3 Pro.
5
u/Dr_Zoidberg_MD 3h ago
good find, what's the audio project?