livekit / client-sdk-swift

LiveKit Swift Client SDK. Easily build live audio or video experiences into your mobile app, game or website.
https://livekit.io
Apache License 2.0
174 stars 84 forks source link

ConnectionState does not match the connection state within LivekitSDK (didUpdateConnectionState not updating) #367

Open michaelbutler1998 opened 2 months ago

michaelbutler1998 commented 2 months ago

Describe the bug

connectionState still appears to be .connected (didUpdateConnectionState is not called to alert about .disconnect) when you lose connection for a prolonged period (around 15+ seconds), but the LiveKitSDK can see that you should be in .disconnected

SDK Version 2.0.5

iOS Version 17.4.1

Steps to Reproduce

  1. Join a call, with another participant active and listening
  2. Turn off your cellular network for 15 seconds.

Whilst you're in this state you can see livekit logs (see log #1 below). When checking connectionState from room, connectionState == .connected.

didUpdateConnectionState is not called to notify that state is now .disconnected

  1. Quickly, toggle mute / unmute when cellular is back on

You now end up in a situation where the listening user cannot hear or communicate with you. If the listening user, or the glitched user rejoins, you can hear each other again.

Expected behavior

  1. During the reconnect, the state should be .reconnecting
  2. connectionState is updated when Livekit is aware of .disconnection, so that we can prevent users from turning their mic on/off when not connected

Logs Please provide logs if you can.

Log #1 - \`\`\`
2024-04-19T14:23:14+0100 error LiveKitSDK : \[LiveKit\] SignalClient.*sendRequest(*:) connectionState is .disconnected
2024-04-19T14:23:14+0100 error LiveKitSDK : \[LiveKit\] Engine.transport(\_:didGenerateIceCandidate:) Failed to send iceCandidate, error: Error Domain=io.livekit.swift-sdk Code=104 "Invalid state(connectionState is .disconnected)" UserInfo={NSLocalizedDescription=Invalid state(connectionState is .disconnected)}
buttjer commented 2 months ago

I want to point out that I receive reconnecting logs but the state remain connected while being offline. This might be related.

michaelbutler1998 commented 2 months ago

Possibly related bug:

  1. Connect to call with two phones, cellular only on 4G/5G.
  2. With one phone, in your phone's settings, set your connection to 2G
  3. Whilst in 2G, toggle your microphone
  4. Change your phones settings back to 4G
  5. Attempt to communicate / toggle mic etc.

You cannot be heard by the other participant, the same as in the initial bug report.

If you are not using Callkit, you get this error: 2024-04-19T17:16:34+0100 error LiveKitSDK : [LiveKit] Engine.signalClient(_:didReceiveAnswer:) Failed to set remote description, error: Error Domain=org.webrtc.RTC_OBJC_TYPE(RTCPeerConnection) Code=-1 "Failed to set remote answer sdp: Called in wrong state: stable" UserInfo={NSLocalizedDescription=Failed to set remote answer sdp: Called in wrong state: stable}

If you are using Callkit, you get this error: 2024-04-19T16:29:06+0100 error LiveKitSDK : [LiveKit] AudioManager.defaultConfigureAudioSessionFunc(newState:oldState:) Failed to configure audio session with error: Error Domain=NSOSStatusErrorDomain Code=1701737535 "Session activation failed" UserInfo={NSLocalizedDescription=Session activation failed}

hiroshihorie commented 2 months ago

You are watching logs for SignalClient(WebSocket)'s connectionState, instead of Engine's connectionState. The didUpdateConnectionState delegate should match the Engine's connectionState. The SDK finally reports disconnect after several attempts to reconnect the internal SignalClient etc.

Example turning off cellular & wifi on iPhone :

C2AA33AE-ECDB-4213-A8E1-CF2A91B2B6DD

Quickly, toggle mute / unmute when cellular is back on You now end up in a situation where the listening user cannot hear or communicate with you. If the listening user, or the glitched user rejoins, you can hear each other again.

This is another issue I will try to reproduce.

buttjer commented 2 months ago

@hiroshihorie

Thanks for the quick response!

This is how we mute await self.room.localParticipant.unpublishAll()

and unmute try await self.room.localParticipant.setMicrophone(enabled: true)

hiroshihorie commented 2 months ago

Can you try try await self.room.localParticipant.setMicrophone(enabled: false) to mute instead ?

This method is guaranteed to execute exclusively when invoked asynchronously .

michaelbutler1998 commented 2 months ago

@hiroshihorie just tried with this suggestion, however the same issue still occurs unfortunately

Can you try try await self.room.localParticipant.setMicrophone(enabled: false) to mute instead ?

hiroshihorie commented 2 months ago

@michaelbutler1998 Will start investigating this one. It only happens while (internal) reconnecting ?

michaelbutler1998 commented 2 months ago

@michaelbutler1998 Will start investigating this one. It only happens while (internal) reconnecting ?

Sorry I don't know for certain, I have only seen it occur when switching back and forth from 2G

michaelbutler1998 commented 1 month ago

@hiroshihorie any luck with this issue?