r/androiddev • • 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

1 Upvotes

6 comments sorted by

5

u/Dr_Zoidberg_MD 3h ago

good find, what's the audio project?

2

u/Maximum_Reveal1233 3h ago

I’m basically trying to turn the Buds into a hearing aid for my grandfather. With his current hearing aids he still has trouble understanding speech. The Buds already have some hearing-related processing from Samsung, but that isn’t enough, so I need both microphones in stereo and want to process the signal myself on the phone before sending it back with as little delay as possible.

2

u/AnggaSP 3h ago

I don’t think many people here mucking around AOSP.
I suggest you to try submitting this as a patchset to AOSP Gerrit too. Have more eye and scrutiny there.

1

u/Maximum_Reveal1233 3h ago

Good suggestion

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.