I’m using the LiveKit Unity SDK. It works fine in...
# ask-ai
m
I’m using the LiveKit Unity SDK. It works fine in the Unity Editor, but on an iOS device, I’m unable to hear the agent’s voice. I can see the agent’s logs in the transcript, and when I speak, my responses are also logged correctly. However, the agent’s audio is not playing on the iOS device. Has anyone faced a similar issue or can help me with this?
t
Thanks for reaching out, Prashant. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I see you can hear/send audio in the Unity Editor and transcripts show the agent speaking, but the agent's audio doesn't play on iOS. I can help troubleshoot — a few quick questions to narrow this down: 1. Which LiveKit Unity SDK version and Unity version are you using? 2. Which iOS device and iOS version are you testing on? 3. How are you rendering remote audio on the client? Are you using Unity AudioSources attached to tracks, or relying on a native WebRTC audio path? 4. Do you see any audio-related warnings or errors in Xcode device logs when the agent speaks? 5. Is the app requesting/allowed microphone and audio session permissions on iOS? (Have you set Audio session category or configured AVAudioSession anywhere?) 6. Does other audio in the app (e.g., local playback or media) play correctly on the same device? 7. Does the issue occur on both simulator and physical device, or only physical devices? Give those details and I’ll suggest targeted steps to test (e.g., checking AVAudioSession config in Xcode logs, verifying AudioSource hookups, and testing a simple remote-audio playback path). Sources: client-sdk-unity-web | livekit/livekit_composite | DeepWiki | client-sdk-unity | livekit/livekit_composite | DeepWiki
m
1. Which LiveKit Unity SDK version and Unity version are you using? - Unity Version: 6000.0.50f1 (Unity 6) - LiveKit Unity SDK: 1.2.4 - Installed via: Unity Package Manager (Git URL) 2. Which iOS device and iOS version are you testing on? - Device: iPhone 15 Pro Max - iOS Version: 18.2 (based on your mention of "os 26.2" which likely means iOS 18.2) - Processor: A17 Pro - Build: Physical device (not simulator) 3. How are you rendering remote audio on the client? - Using Unity AudioSources attached to tracks (the standard Unity approach) - Code: new AudioStream(audioTrack, audioSource) in LiveKitManager.cs:436 - AudioSource configuration: - Has dummy AudioClip attached (created programmatically) - spatialBlend = 0 (2D audio) - volume = 1.0f - loop = true on the dummy clip - NOT using native WebRTC audio path directly - The AudioStream uses AudioProbe component which implements OnAudioFilterRead callback 4. Do you see any audio-related warnings or errors in Xcode device logs? - No audio-related errors in Xcode console - Native FFI initialization succeeds - No warnings about audio session failures - No codec or format errors - The only indicator is Unity logs showing maxSample: 0.000000 (RingBuffer empty) - Stack traces show UnitySynchronizationContext:Exec() working for other callbacks 5. Is the app requesting/allowed microphone and audio session permissions on iOS? - YES - Microphone permission granted (logs show: [LiveKitManager] Microphone permission granted) - Info.plist includes NSMicrophoneUsageDescription - AVAudioSession was initially configured via custom native plugin (LiveKitAudioSession.mm) but was REMOVED based on investigation (LiveKit SDK should handle it internally) - Previous configuration was: - Category: AVAudioSessionCategoryPlayAndRecord - Mode: AVAudioSessionModeVoiceChat - Sample rate: 48kHz (later changed to 24kHz) - Microphone publishing works (local audio goes to agent, transcripts received) 6. Does other audio in the app play correctly on the same device? - Unity Editor: YES - Agent audio plays perfectly - iOS Device - Other Unity audio: Not tested with other audio sources - iOS Device - LiveKit agent audio: NO - Silent (the issue) - The dummy AudioClip loops correctly (time value cycles 0-1 second), proving AudioSource is active - OnAudioFilterRead is called 1000+ times, proving Unity audio pipeline is active - The issue is specifically that the AudioStream's RingBuffer never receives data 7. Does the issue occur on both simulator and physical device, or only physical devices? - Physical Device (iPhone 15 Pro Max): Issue occurs - NO audio - Unity Editor (macOS): Works perfectly - audio plays correctly - iOS Simulator: Not tested - The problem is iOS device-specific (Editor vs Device, not Unity vs Native) Additional Technical Details What Works on iOS: - ✅ Room connection - ✅ Track subscription (AudioTrack from agent) - ✅ Microphone capture and publishing - ✅ Text transcripts (DataReceived callbacks) - ✅ AudioSource.Play() (dummy clip loops) - ✅ OnAudioFilterRead called continuously - ✅ SynchronizationContext exists and patched - ✅ All non-audio FFI callbacks work What Fails on iOS: - ❌ AudioStreamEvent callbacks never fire - ❌ OnAudioStreamEvent() in AudioStream.cs never called - ❌ RingBuffer stays empty (no audio data) - ❌ No sound heard from agent
t
Thanks — I’m responding to your detailed report that Editor audio works but on iOS the AudioStream’s native→managed callbacks never fire and the ring buffer stays empty. Great info; that narrows this to the native‑to‑managed audio delivery on iOS. Please try these focused checks (short, ordered steps) and tell me the results: 1. Confirm inbound audio bytes with stats ◦ Call
GetStats()
for the room and check inbound audio
bytesReceived
/
packetsReceived
. ◦ If bytes increase, the remote audio is arriving over RTP and the problem is rendering (native→managed path). If bytes do not increase, signaling/RTP is the issue. 1. Add explicit AudioStream event logging (verify callback registration) ◦ Immediately after creating
AudioStream(audioTrack, audioSource)
, attach a handler that logs every event and a timestamp. ◦ If the handler never logs on the device but logs in Editor, native callbacks are not being invoked. 1. Try the SDK’s minimal example on the same device ◦ Build and run the official LiveKit Unity demo/example with your same iOS/Xcode settings. ◦ If the example works, the problem is in your app or build settings. If it fails, it’s SDK + environment related. 1. Bypass custom audio probe/path (isolate Unity rendering) ◦ Temporarily stop using `AudioProbe`/OnAudioFilterRead and
AudioStream
. Try the SDK’s simplest attach/render path (or attach track to an AudioSource if supported). ◦ If that plays audio, the issue is in the custom audio processing or ring buffer usage. 1. Check IL2CPP/stripping and plugin linking settings ◦ Player Settings (iOS): set Managed Stripping Level = Disabled/Low, Disable Engine Code Stripping, ensure Architecture = ARM64, Target SDK = Device. ◦ Build with Development and Script Debugging enabled. ◦ Re-run — a high stripping level can remove pinvoke glue or cause delegate GC issues. 1. Confirm native callback pinning / GC safety ◦ Ensure the managed delegate passed to native is stored/pinned so the GC cannot collect it. (Log when you register/unregister.) ◦ On iOS/IL2CPP, delegate lifetimes and AOT differences can break callbacks. 1. Validate AVAudioSession activity at runtime ◦ In Xcode console, log any AVAudioSession activation calls. Confirm category/mode set to PlayAndRecord/VoiceChat and session is Active when subscribing to audio. ◦ If SDK should manage it, confirm it actually calls setActive on the device. 1. Try Unity LTS (quick compatibility test) ◦ Create a tiny project in Unity 2022 LTS with LiveKit SDK 1.2.4 and test the same device/build. ◦ If audio works there, Unity 6 likely introduces an incompatibility with the native plugin or IL2CPP behavior. 1. Inspect Xcode logs for native callback traces and thread context ◦ Filter logs for
webrtc
,
audio
, or your plugin symbol names to see whether the native path is producing frames or failing to call the managed entrypoint. ◦ Note whether callbacks appear on non-main threads (threading/marshaling issues). What I can help next if you report results: • If stats show inbound bytes increasing but no AudioStream events: I’ll provide exact debug logging snippets and a minimal repro checklist to isolate native callback registration and delegate pinning. • If stats show no inbound bytes: I’ll guide further network/RTP/signaling traces. • If the example works but your app fails: I’ll suggest targeted build setting diffs to check. Which step can you run first and share results for?