Skip to content

Audio routing issue #322

Description

@hehooleehoo

On iOS, when joining a LiveKit room without the local microphone enabled, remote audio plays through the physical earpiece (receiver) instead of the bottom loudspeaker, despite using configureAudio({ ios: { defaultOutput: "speaker" } }), selectAudioOutput("force_speaker"), and setAppleAudioConfiguration. The only reliable workaround is briefly enabling the microphone, which causes an audible bleep and risks transmitting audio when users should not speak (listen-only sessions).

To Reproduce

Steps to reproduce the behavior:

  1. Create an Expo app with @livekit/react-native, @livekit/react-native-webrtc, call registerGlobals() at startup
  2. Connect to a LiveKit room with remote audio (e.g. host speaking) using the connect flow below
  3. Join without enabling the microphone
  4. Hold phone at arm's length — audio is inaudible (routed to earpiece)
  5. Enable microphone — audio immediately switches to loudspeaker ✅

Minimal connect flow:

await AudioSession.configureAudio({ ios: { defaultOutput: 'speaker' } });
await AudioSession.startAudioSession();
// selectAudioOutput before connect throws OSStatus -50
await room.connect(url, token);
// After connect: selectAudioOutput + setAppleAudioConfiguration have no effect
if (Platform.OS === 'ios') {
  await AudioSession.setAppleAudioConfiguration({
    audioCategory: 'playAndRecord',
    audioCategoryOptions: ['defaultToSpeaker', 'allowBluetooth', 'allowBluetoothA2DP', 'allowAirPlay'],
    audioMode: 'videoChat',
  });
  await AudioSession.selectAudioOutput('force_speaker');
}

Expected behavior

  • Audio should route to loudspeaker when defaultOutput: "speaker" is set
  • selectAudioOutput("force_speaker") should work after connect without errors
  • selectAudioOutput before connect should not throw OSStatus -50

Screenshots

N/A — audio routing behavior.

Device Info:

  • Device: testing on iPhone 13
  • OS: iOS 26.2.1

Dependencies Info (please reference your package-lock.json or yarn.lock file, not just your package.json):

  • @livekit/react-native: 2.9.6
  • livekit-client: 2.16.1
  • react-native-webrtc: @livekit/react-native-webrtc 137.0.2

Additional context

What we've tried (none work):

  • selectAudioOutput("force_speaker") before connect → throws OSStatus -50 (paramErr)
  • selectAudioOutput + setAppleAudioConfiguration at 100ms, 300ms, 800ms, 2s, 4s after connect → no error, no effect
  • room.on("trackSubscribed", ...) → apply config when first remote audio subscribes → no effect
  • Patched selectAudioOutput to use RTCAudioSession instead of AVAudioSession → OSStatus -50, connection fails
  • showAudioRoutePicker() shows Speaker selected, but physical output is still earpiece → suggests session/config mismatch

Behavior summary:

Scenario Result
Join (no mic) ❌ Earpiece
Join with Bluetooth ❌ Earpiece
Bluetooth disconnect mid-call ❌ Earpiece (expected: loudspeaker)
Enable mic ✅ Loudspeaker
If speaker already on → BT connect → BT disconnect ✅ Loudspeaker

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions