Skip to content

feat: configure the iOS audio session natively in the default path#434

Draft
hiroshihorie wants to merge 5 commits into
mainfrom
hiroshi/native-audio-session
Draft

feat: configure the iOS audio session natively in the default path#434
hiroshihorie wants to merge 5 commits into
mainfrom
hiroshi/native-audio-session

Conversation

@hiroshihorie

@hiroshihorie hiroshihorie commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

setupIOSAudioManagement's default path now pushes the audio-session policy to native via AudioDeviceModule.setAutomaticAudioSessionConfiguration() instead of registering willEnable/didDisable JS handlers, so the audio engine's worker thread no longer round-trips to JS in the stock path. That round trip could stall or deadlock engine operations when the JS thread was itself blocked in a synchronous bridge call (livekit/react-native-webrtc#89). Custom configurations via onConfigureNativeAudio keep the JS handler path, still bounded by the native wait timeout.

  • Repeated setup calls supersede the previous setup by claiming a token (stale cleanup functions become no-ops), and each path arms its own mechanism before tearing down the other's so the engine hooks stay owned throughout a switch.
  • Switching paths mid-call is documented as unsupported: switching away from a custom setup mid-call abandons the audio session activation its handlers took, and with the shared activation count nobody releases it. Switch while disconnected.
  • The onConfigureNativeAudio contract is documented: it runs under a bounded native wait and must not call into the WebRTC engine or a peer connection.
  • Example Podfile.lock synced with the WebRTC-SDK 144.7559.10 pin. Changeset included (minor).

Dependency

Depends on livekit/react-native-webrtc#96. CI here installs @livekit/react-native-webrtc from the registry, which does not yet ship setAutomaticAudioSessionConfiguration, so typecheck stays red until that PR merges, a release is cut, and the dependency here is bumped. Local verification was done against the linked fork.

Testing

  • tsc clean for src/ against the linked fork branch (including the fork's literal-union types).
  • Device smoke test (iPhone, iOS 26.5.2) with the example app: connect, publish mic (duplex engine recreate), mute toggles, disconnect. No freeze, zero bounded-wait timeouts or native config failures in the unified log, and the system audio records show the session ran with the default policy and ended inactive at teardown.

Before undrafting

setupIOSAudioManagement's default path now pushes the audio-session
policy to native via
AudioDeviceModule.setAutomaticAudioSessionConfiguration() instead of
registering willEnable/didDisable JS handlers, so the audio engine's
worker thread no longer round-trips to JS in the stock path. That round
trip could stall or deadlock engine operations when the JS thread was
itself blocked in a synchronous bridge call. Custom configurations
(onConfigureNativeAudio) keep the JS handler path, still bounded by the
native wait timeout.

Repeated setup calls and switches between the default and custom paths
are safe: each setup supersedes the previous one by claiming a token,
stale cleanup functions become no-ops, and each path arms its own
mechanism before tearing down the other's so the engine hooks stay
owned throughout a switch.
Spell out that the custom callback runs inside the audio engine's
lifecycle callbacks under a bounded native wait, so it must return
quickly and must not call into the WebRTC engine or a peer connection.
Doing so can block on the very engine operation the callback is holding
up, stalling it until the wait times out.

Also note that the default path involves no JavaScript per transition,
that repeated setup calls supersede the previous one, and that switching
paths is best done while disconnected.
@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 80f04c5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@livekit/react-native Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@hiroshihorie hiroshihorie requested a review from davidliu July 9, 2026 16:14
The previous wording claimed a switch during an active call takes full
effect from the next engine transition. That undersold the failure
mode: switching away from a custom setup mid-call abandons the audio
session activation its handlers took, and with the shared activation
count nobody releases it, so the session can stay active after the call
ends. State it as unsupported with the concrete consequence.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant