debug: add logging to trace call signaling flow

Temporary diagnostic logging to identify why calls hang at
Connecting. Logs added to:
- CallManager.onSignalingEvent: event kind, age, state
- CallController: answer received, ICE candidates (buffered vs
  direct), flush count, local ICE generation

https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
Claude
2026-04-02 02:12:37 +00:00
parent ca21a8489f
commit 8354bcd616
2 changed files with 14 additions and 3 deletions
@@ -177,6 +177,7 @@ 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),
)
@@ -188,12 +189,14 @@ class CallController(
try {
val candidate = parseIceCandidate(json)
if (webRtcSession != null && remoteDescriptionSet) {
Log.d(TAG) { "Adding ICE candidate directly: ${candidate.sdp.take(50)}" }
webRtcSession?.addIceCandidate(candidate)
} else {
Log.d(TAG) { "Buffering ICE candidate (session=${webRtcSession != null}, remoteSet=$remoteDescriptionSet)" }
pendingIceCandidates.add(candidate)
}
} catch (_: Exception) {
// Ignore malformed ICE candidates
} catch (e: Exception) {
Log.e(TAG, "Failed to parse ICE candidate: $json", e)
}
}
@@ -201,6 +204,7 @@ class CallController(
remoteDescriptionSet = true
val session = webRtcSession ?: return
val candidates = pendingIceCandidates.toList()
Log.d(TAG) { "Flushing ${candidates.size} buffered ICE candidates" }
pendingIceCandidates.clear()
candidates.forEach { session.addIceCandidate(it) }
}
@@ -309,6 +313,7 @@ class CallController(
}
private fun onLocalIceCandidate(candidate: IceCandidate) {
Log.d(TAG) { "Local ICE candidate: ${candidate.sdp.take(50)}" }
val callId = currentCallId ?: return
val peerPubKey = currentPeerPubKey ?: return
val candidateJson = serializeIceCandidate(candidate)
@@ -31,6 +31,7 @@ import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallIceCandidateEvent
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallOfferEvent
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRejectEvent
import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallType
import com.vitorpamplona.quartz.utils.Log
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -198,9 +199,14 @@ class CallManager(
}
fun onSignalingEvent(event: Event) {
if (isEventTooOld(event)) return
if (isEventTooOld(event)) {
Log.d("CallManager") { "Discarding old event kind=${event.kind} age=${TimeUtils.now() - event.createdAt}s" }
return
}
if (!processedEventIds.add(event.id)) return
Log.d("CallManager") { "Processing signaling event kind=${event.kind} id=${event.id.take(8)} state=${_state.value::class.simpleName}" }
when (event) {
is CallOfferEvent -> onIncomingCallEvent(event)
is CallAnswerEvent -> onCallAnswered(event)