fix: guard against stale SDP answers in wrong signaling state
Our own renegotiation answers can echo back through the relay and get processed as if from the peer. Check that the peer connection is in HAVE_LOCAL_OFFER state before applying a remote answer SDP, preventing the "Called in wrong state: stable" error. https://claude.ai/code/session_014espsysob7MrE8X8e75jFX
This commit is contained in:
@@ -40,6 +40,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.webrtc.IceCandidate
|
||||
import org.webrtc.PeerConnection
|
||||
import org.webrtc.SessionDescription
|
||||
import org.webrtc.VideoFrame
|
||||
import org.webrtc.VideoSink
|
||||
@@ -228,8 +229,18 @@ class CallController(
|
||||
}
|
||||
|
||||
fun onCallAnswerReceived(sdpAnswer: String) {
|
||||
Log.d(TAG) { "Answer received, SDP length=${sdpAnswer.length}, session=${webRtcSession != null}" }
|
||||
webRtcSession?.setRemoteDescription(SessionDescription(SessionDescription.Type.ANSWER, sdpAnswer))
|
||||
val session = webRtcSession ?: return
|
||||
val signalingState = session.getSignalingState()
|
||||
Log.d(TAG) { "Answer received, SDP length=${sdpAnswer.length}, signalingState=$signalingState" }
|
||||
|
||||
// An answer is only valid when we have a pending local offer.
|
||||
// Ignore stale answers (e.g. our own renegotiation answer echoed back by the relay).
|
||||
if (signalingState != PeerConnection.SignalingState.HAVE_LOCAL_OFFER) {
|
||||
Log.d(TAG) { "Ignoring answer in $signalingState state (no pending local offer)" }
|
||||
return
|
||||
}
|
||||
|
||||
session.setRemoteDescription(SessionDescription(SessionDescription.Type.ANSWER, sdpAnswer))
|
||||
flushPendingIceCandidates()
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +263,8 @@ class WebRtcCallSession(
|
||||
peerConnection?.addIceCandidate(candidate)
|
||||
}
|
||||
|
||||
fun getSignalingState(): PeerConnection.SignalingState? = peerConnection?.signalingState()
|
||||
|
||||
fun setAudioEnabled(enabled: Boolean) {
|
||||
localAudioTrack?.setEnabled(enabled)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user