From 04603cfe2d6674b44572725ee6c9de0ffa491699 Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 7 Dec 2025 11:13:24 +0100 Subject: [PATCH] Add detailed ICE candidate exchange logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive logging to track WebRTC ICE candidate exchange: - Log local candidate generation with type (host/srflx/relay) - Log when candidates are sent to signaling server - Log remote candidate reception and addition - Log ICE gathering state changes - Log ICE connection state changes - Enhanced ICE error logging with details This will help diagnose connection issues and TURN server problems. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/peer/exchanging-ice-state.ts | 13 +++++++++++-- src/peer/index.ts | 25 ++++++++++++++++++++++++- src/peer/state.ts | 9 ++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/peer/exchanging-ice-state.ts b/src/peer/exchanging-ice-state.ts index 6b68680..5724ee0 100644 --- a/src/peer/exchanging-ice-state.ts +++ b/src/peer/exchanging-ice-state.ts @@ -40,13 +40,22 @@ export class ExchangingIceState extends PeerState { this.lastIceTimestamp ); + if (candidates.length > 0) { + console.log(`📥 Received ${candidates.length} remote ICE candidate(s)`); + } + for (const cand of candidates) { if (cand.candidate && cand.candidate.candidate && cand.candidate.candidate !== '') { + const type = cand.candidate.candidate.includes('typ host') ? 'host' : + cand.candidate.candidate.includes('typ srflx') ? 'srflx' : + cand.candidate.candidate.includes('typ relay') ? 'relay' : 'unknown'; + console.log(`🧊 Adding remote ${type} ICE candidate:`, cand.candidate.candidate); try { await this.peer.pc.addIceCandidate(new this.peer.RTCIceCandidate(cand.candidate)); + console.log(`✅ Added remote ${type} ICE candidate`); this.lastIceTimestamp = cand.createdAt; } catch (err) { - console.warn('Failed to add ICE candidate:', err); + console.warn(`⚠️ Failed to add remote ${type} ICE candidate:`, err); this.lastIceTimestamp = cand.createdAt; } } else { @@ -54,7 +63,7 @@ export class ExchangingIceState extends PeerState { } } } catch (err) { - console.error('Error polling for ICE candidates:', err); + console.error('❌ Error polling for ICE candidates:', err); if (err instanceof Error && err.message.includes('not found')) { this.cleanup(); const { FailedState } = await import('./failed-state.js'); diff --git a/src/peer/index.ts b/src/peer/index.ts index db54ad2..c2a47a2 100644 --- a/src/peer/index.ts +++ b/src/peer/index.ts @@ -105,18 +105,23 @@ export default class RondevuPeer extends EventEmitter { */ private setupPeerConnection(): void { this.connectionStateChangeHandler = () => { + console.log(`🔌 Connection state changed: ${this.pc.connectionState}`); switch (this.pc.connectionState) { case 'connected': + console.log('✅ WebRTC connection established'); this.setState(new ConnectedState(this)); this.emitEvent('connected'); break; case 'disconnected': + console.log('⚠️ WebRTC connection disconnected'); this.emitEvent('disconnected'); break; case 'failed': + console.log('❌ WebRTC connection failed'); this.setState(new FailedState(this, new Error('Connection failed'))); break; case 'closed': + console.log('🔒 WebRTC connection closed'); this.setState(new ClosedState(this)); this.emitEvent('disconnected'); break; @@ -124,6 +129,18 @@ export default class RondevuPeer extends EventEmitter { }; this.pc.addEventListener('connectionstatechange', this.connectionStateChangeHandler); + // Add ICE connection state logging + const iceConnectionStateHandler = () => { + console.log(`🧊 ICE connection state: ${this.pc.iceConnectionState}`); + }; + this.pc.addEventListener('iceconnectionstatechange', iceConnectionStateHandler); + + // Add ICE gathering state logging + const iceGatheringStateHandler = () => { + console.log(`🔍 ICE gathering state: ${this.pc.iceGatheringState}`); + }; + this.pc.addEventListener('icegatheringstatechange', iceGatheringStateHandler); + this.dataChannelHandler = (event: RTCDataChannelEvent) => { this.emitEvent('datachannel', event.channel); }; @@ -135,7 +152,13 @@ export default class RondevuPeer extends EventEmitter { this.pc.addEventListener('track', this.trackHandler); this.iceCandidateErrorHandler = (event: Event) => { - console.error('ICE candidate error:', event); + const iceError = event as RTCPeerConnectionIceErrorEvent; + console.error(`❌ ICE candidate error: ${iceError.errorText || 'Unknown error'}`, { + errorCode: iceError.errorCode, + url: iceError.url, + address: iceError.address, + port: iceError.port + }); }; this.pc.addEventListener('icecandidateerror', this.iceCandidateErrorHandler); } diff --git a/src/peer/state.ts b/src/peer/state.ts index a899b61..a150768 100644 --- a/src/peer/state.ts +++ b/src/peer/state.ts @@ -40,12 +40,19 @@ export abstract class PeerState { if (event.candidate && this.peer.offerId) { const candidateData = event.candidate.toJSON(); if (candidateData.candidate && candidateData.candidate !== '') { + const type = candidateData.candidate.includes('typ host') ? 'host' : + candidateData.candidate.includes('typ srflx') ? 'srflx' : + candidateData.candidate.includes('typ relay') ? 'relay' : 'unknown'; + console.log(`🧊 Generated ${type} ICE candidate:`, candidateData.candidate); try { await this.peer.offersApi.addIceCandidates(this.peer.offerId, [candidateData]); + console.log(`✅ Sent ${type} ICE candidate to server`); } catch (err) { - console.error('Error sending ICE candidate:', err); + console.error(`❌ Error sending ${type} ICE candidate:`, err); } } + } else if (!event.candidate) { + console.log('🧊 ICE gathering complete (null candidate)'); } }; this.peer.pc.addEventListener('icecandidate', this.iceCandidateHandler);