You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since #206 (624fa1d), WebRtcVoiceSendChannel::MuteStream stops the ADM's recording when all send streams are muted, unless the ADM overrides IsStopOnMuteModeEnabled() to false. The iOS/macOS AudioEngineDevice opts out and mutes internally while keeping capture alive; the Android ADM has no override, so muting an audio track now fully releases AudioRecord.
Per the guidance in #246 — platforms that properly implement the ADM's Mute API can opt out individually — this issue proposes doing exactly that for Android.
Problem
For push-to-talk style apps, re-enabling the mic is a cold start: a new AudioRecord, AGC reconvergence, and on USB audio devices a full interface renegotiation (alternate setting selection, bandwidth reservation, sample rate setup). Speech during that window is lost, heard as a clipped first word on every transmission. Before #206, muting kept capture warm on Android.
Android already has a working warm-mute implementation — WebRtcAudioRecord.setMicrophoneMute() zero-fills the capture buffer on the record thread (sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java) — but it is only reachable from Java. The C++ AndroidAudioDeviceModule::SetMicrophoneMute() returns -1 "Not implemented" (sdk/android/src/jni/audio_device/audio_device_module.cc), so the fallback path in MuteStream is a no-op on Android, and there is no way to opt out of stop-on-mute.
Proposal
Keep stop-on-mute as the Android default; make the mute API real and the opt-out possible:
Implement SetMicrophoneMute on the Android ADM: bridge AndroidAudioDeviceModule::SetMicrophoneMute() through AudioRecordJni to the existing WebRtcAudioRecord.setMicrophoneMute(), so the non-stop mute path zeroes audio at the source — the same "mute inside the engine, capture stays alive" semantics as the iOS AudioEngineDevice.
Builder opt-out: add JavaAudioDeviceModule.Builder.setStopRecordingOnMute(boolean), default true (current behavior unchanged), plumbed through nativeCreateAudioDeviceModule into AndroidAudioDeviceModule, which overrides IsStopOnMuteModeEnabled() accordingly.
This mirrors the existing useStereoInput plumbing and is fully backward compatible. We understand the trade-off the default protects (OS mic-in-use indicator turns off while muted); apps that opt out accept the indicator staying on in exchange for warm capture.
Happy to submit a PR for this if the approach sounds acceptable.
Context
Regression surfaced in LiveKit Android (io.github.webrtc-sdk:android builds containing 624fa1d, i.e. 137.7151.05+) for a PTT app using USB handset microphones. LiveKit Android v2.23.0 (webrtc 137.7151.04) is the last unaffected release; v2.23.1 (137.7151.05) the first affected.
Current workaround: publish the mic once and gate PTT with the ADM-level setMicrophoneMute from the app, which forfeits track-level mute semantics (server mute state, remote TrackMuted events) and transmits encoded silence for the call duration.
Summary
Since #206 (624fa1d),
WebRtcVoiceSendChannel::MuteStreamstops the ADM's recording when all send streams are muted, unless the ADM overridesIsStopOnMuteModeEnabled()to false. The iOS/macOSAudioEngineDeviceopts out and mutes internally while keeping capture alive; the Android ADM has no override, so muting an audio track now fully releasesAudioRecord.Per the guidance in #246 — platforms that properly implement the ADM's Mute API can opt out individually — this issue proposes doing exactly that for Android.
Problem
For push-to-talk style apps, re-enabling the mic is a cold start: a new
AudioRecord, AGC reconvergence, and on USB audio devices a full interface renegotiation (alternate setting selection, bandwidth reservation, sample rate setup). Speech during that window is lost, heard as a clipped first word on every transmission. Before #206, muting kept capture warm on Android.Android already has a working warm-mute implementation —
WebRtcAudioRecord.setMicrophoneMute()zero-fills the capture buffer on the record thread (sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java) — but it is only reachable from Java. The C++AndroidAudioDeviceModule::SetMicrophoneMute()returns -1 "Not implemented" (sdk/android/src/jni/audio_device/audio_device_module.cc), so the fallback path inMuteStreamis a no-op on Android, and there is no way to opt out of stop-on-mute.Proposal
Keep stop-on-mute as the Android default; make the mute API real and the opt-out possible:
SetMicrophoneMuteon the Android ADM: bridgeAndroidAudioDeviceModule::SetMicrophoneMute()throughAudioRecordJnito the existingWebRtcAudioRecord.setMicrophoneMute(), so the non-stop mute path zeroes audio at the source — the same "mute inside the engine, capture stays alive" semantics as the iOSAudioEngineDevice.JavaAudioDeviceModule.Builder.setStopRecordingOnMute(boolean), defaulttrue(current behavior unchanged), plumbed throughnativeCreateAudioDeviceModuleintoAndroidAudioDeviceModule, which overridesIsStopOnMuteModeEnabled()accordingly.This mirrors the existing
useStereoInputplumbing and is fully backward compatible. We understand the trade-off the default protects (OS mic-in-use indicator turns off while muted); apps that opt out accept the indicator staying on in exchange for warm capture.Happy to submit a PR for this if the approach sounds acceptable.
Context
io.github.webrtc-sdk:androidbuilds containing 624fa1d, i.e. 137.7151.05+) for a PTT app using USB handset microphones. LiveKit Android v2.23.0 (webrtc 137.7151.04) is the last unaffected release; v2.23.1 (137.7151.05) the first affected.AudioEngineDeviceopt-out in AVAudioEngine version AudioDeviceModule #158/Change default to stop recording when muted #206.setMicrophoneMutefrom the app, which forfeits track-level mute semantics (server mute state, remoteTrackMutedevents) and transmits encoded silence for the call duration.