← All investigations
// investigation #001 · Android · WebRTC · 20 Jun 2026

Why the Android 12 Mic Indicator Wouldn't Turn Off — A WebRTC Engine Investigation

"Says I'm muted but the mic light is still on. Are you recording me?? Uninstalling."

I have a soft spot for bugs like this one. On the surface, everything looked perfect — the app said muted, audio stopped going out, the code was clean. And users were still furious. Because Android's little green mic dot kept glowing after they hit mute, like the app was quietly listening in. For a video-calling app, that's about the scariest review you can get. So I started pulling threads… and didn't stop until I was inside the WebRTC engine itself.

What users were seeing

The symptom was annoyingly precise — and easy to reproduce:

And here's the detail I kept coming back to: it only happened on Android 12+. On older phones, everything was fine. Whenever a bug shows up on exactly one OS version, the first thing I do is go read what changed in that release. That habit saved me here.

Chasing it down

Before blaming anything exotic, I ruled out the boring explanations — because it's usually the boring one:

That last point flipped the whole thing around for me. Those green/orange dots don't care what my app thinks it's doing — they react to whether the OS sees a live audio-capture session, full stop. The dot stays lit until the system gets a "stop," and even then it lingers for a few seconds by design. So I stopped staring at my own mute logic and asked a different question: when the user is "muted," does the operating system still think the mic is open?

It did. And once I understood why, the whole thing made sense.

The actual root cause

Here's the part you'd basically never catch from the app side: muting a WebRTC call doesn't turn the microphone off.

Under the hood, the capture loop in WebRtcAudioRecord keeps an AudioRecord instance happily reading from the mic the entire time. "Mute" is usually just it quietly throwing the samples away — zeroing them out before they ever get encoded or sent. To the user, it's silence. To Android 12, the mic is still wide open, because nothing ever told AudioRecord to stop.

So the app was honest about muting. The engine just never passed that message along to the OS. For years nobody noticed — until Android 12 put a literal spotlight on it and turned a harmless shortcut into a "is this app spying on me?" moment.

// WebRTC audio capture thread (simplified)
private void audioThreadProcess() {
  while (keepAlive) {
    int bytes = audioRecord.read(byteBuffer, capacity);

    if (microphoneMute) {
      // "mute" = wipe the samples, but keep recording
      byteBuffer.clear();
      byteBuffer.put(emptyBytes);
    }
    nativeDataIsRecorded(bytes); // session still active → OS keeps mic dot on
  }
}

Before: muting discards the audio, but the AudioRecord keeps capturing.

User taps Mute the app correctly shows “muted” WebRTC zeroes the samples audio is silenced before encoding AudioRecord — STILL RECORDING the capture session is never stopped Android 12: mic indicator STAYS ON the OS still sees an active mic session
Fig 1 — The bug: silencing audio isn't the same as stopping the microphone.

Fixing it

The fix had to live where the problem actually was — in the engine, not the app. So instead of "muting" by tossing samples while the mic kept running, I made mute do the honest thing: stop and release the capture, then spin it back up on un-mute. The moment the session genuinely stops, the OS gets its "stop" signal and the green dot starts clearing on its own.

Since this all lives in the WebRTC SDK and not the app, I patched WebRtcAudioRecord.java in the engine source, built a custom WebRTC AAR, and dropped it in to replace the stock one. I sent the fix upstream as well — it's public, so you don't have to take my word for any of this: WebRTC change 340200.

public void setMicrophoneMute(boolean mute) {
  this.microphoneMute = mute;

  if (mute) {
    stopRecording();   // actually release the AudioRecord session
  } else {
    startRecording();  // re-initialize capture on un-mute
  }
}

After: muting genuinely stops capture, so the OS clears the indicator.

User taps Mute same tap, new behaviour underneath setMicrophoneMute(true) intercept the mute call in the engine stopRecording() — release AudioRecord the capture session genuinely stops Android 12: indicator clears the OS receives the stop signal
Fig 2 — The fix: muting stops capture, so the OS turns the indicator off.

The payoff

The change was small, but the effect was immediate:

What I took away from it

A few lessons from this one that I keep running into:


This is the kind of problem that hides below the surface — and chasing things like it is what FixMyApp does best: deep engineering, root-cause investigation, and fixes for Mobile, Web, and Real-Time applications. Whether you need an urgent rescue, help getting an AI-built app live, or want to launch an idea in 30 days — reach out for a quote.

Request a quote / Let's talk