Repository navigation
iOS app: WebView microphone capture is muted when the app goes to the background or the screen locks #5698
Description
Summary
In the bb iOS app, microphone capture inside the WebView stops the moment the app goes to the background or the screen locks. The MediaStreamTrack from getUserMedia gets a system mute event while the AudioContext keeps running and the WebSocket stays open. I expected capture to continue while the page holds an active play-and-record audio session, as it does in apps that declare background audio.
This hits every audio feature that runs in the WebView: the built-in voice input in the prompt box, and plugins that do realtime audio (I found it while building a plugin that runs voice calls with agents).
Versions and environment
- bb iOS app (App Store build, rendering bb in WKWebView via
react-native-webview), iPhone on iOS 18.7. User agent:iPhone OS 18_7 ... AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148. - bb server 0.46.1 (npm
bb-app), macOS. - Code read at
get-bb/bb@6a639cfc0d66e0c789a1bd7309266973228d1a80andWebKit/WebKit@2d1c22173231e23bb5dbfb1485a85f482fa0b993.
Steps to reproduce
- Open bb in the iOS app.
- Start microphone capture in the page: the prompt box voice input, or any plugin that calls
navigator.mediaDevices.getUserMedia({ audio: true }). Optionally setnavigator.audioSession.type = "play-and-record"first; it does not change the result. - Add listeners:
track.onmute,track.onunmute,document.onvisibilitychange, and logaudioContext.state. - Switch to another app (or lock the screen) for a few seconds, then come back.
Expected vs actual
Actual (times relative to the start of capture):
+0 s navigator.audioSession.type = "play-and-record"; capture started, track live
+3 s visibilitychange: document.hidden = true (switched apps)
+3 s MediaStreamTrack "mute" with document.hidden = true (system mute; the page did not mute it)
AudioContext.state stays "running"; WebSocket stays open
+9 s visibilitychange: document.hidden = false (back in bb)
+9 s MediaStreamTrack "unmute" by itself
Expected:
The track stays unmuted while the app is in the background, and audio keeps flowing.
Only capture is cut, and it is cut by the system. Nothing in the page asked for it.
Evidence
Root cause is in WebKit, driven by the host app's Info.plist:
- When the document is hidden, WebKit mutes microphone capture if the
interruptAudioOnPageVisibilityChangeEnabledsetting is on:Document.cpp#L6500-L6509. - The UI process (the host app) sets that preference from
RealtimeMediaSourceCenter::shouldInterruptAudioOnPageVisibilityChange():WebPreferencesCocoa.mm#L149. - On iOS that function returns
trueunless the main bundle'sUIBackgroundModescontainsaudio:RealtimeMediaSourceCenterCocoa.mm#L35-L51. The same check also gates muting of speech recognition when the page is hidden:WebProcessProxy.cpp#L3266-L3275. - WebKit's own test covers this behavior:
LayoutTests/platform/ios/mediastream/audio-muted-in-background-tab.html. It was added in WebKit bug 198307, "Add an option to mute audio capture automatically when page is not visible".
bb's iOS app declares only remote-notification: apps/mobile/app.json#L28. So WebKit mutes capture every time the app is backgrounded. The app does not configure AVAudioSession itself; WebKit manages the session for the page. react-native-webview 13.16.1 only touches audio when ignoreSilentHardwareSwitch is set, and bb does not set it.
What you ruled out
- Not the page muting itself: the mute arrives with
document.hidden = trueand no page code callsenabled = falseor stops the track. - Not the audio graph or the network: the
AudioContextstaysrunningand the WebSocket stays open during the mute. navigator.audioSession.type = "play-and-record"does not help. The mute decision in WebKit does not look at it.- I did not find an existing issue or PR for
UIBackgroundModesor background microphone capture. - I did not reproduce on a device build from
main. I observed it in the App Store build.mainstill declares onlyremote-notification, so the same check applies.
Suggested priority and effort
Medium. It affects every iPhone user of voice input or audio plugins whenever they leave the app. No data is lost, but the only workaround is to keep bb in the foreground with the screen on. Effort: low, a one-line Info.plist change. PR follows.
AGENT GENERATED
Activity
bb-slop-cop commentedon Oct 17, 2026
🚨 SLOP COP 🚨 ·
new-issue-autopilotmobile(all previously unset).partial-repro.6a639cfc0: both production and dev iOS plists omit background audio while permitting microphone use. Frozen installs and all 67 full-build tasks pass.lucascastellanibr commentedon Oct 17, 2026
The fix for this issue is ready in #5700: one line in
apps/mobile/app.jsonthat adds"audio"toUIBackgroundModes. It builds for the iOS Simulator, and the generatedInfo.plistcontains the key.The contributor gate closed #5700 automatically because I'm not on the allow list yet. Could a maintainer
/approve @lucascastellanibron #5700 and reopen it? If you'd rather apply the one-line change yourselves, that works just as well. I'm happy to test on a device.