@@ -39,6 +39,7 @@ export function useWebRTC({ entityId, enabled = true }: UseWebRTCOptions): UseWe
3939 const peerConnectionRef = useRef < RTCPeerConnection | null > ( null )
4040 const initializingRef = useRef < boolean > ( false )
4141 const pendingInitRef = useRef < boolean > ( false )
42+ const pendingCandidatesRef = useRef < RTCIceCandidateInit [ ] > ( [ ] )
4243 const [ isStreaming , setIsStreaming ] = useState ( false )
4344 const [ error , setError ] = useState < string | null > ( null )
4445 const [ retryCount , setRetryCount ] = useState ( 0 )
@@ -51,6 +52,7 @@ export function useWebRTC({ entityId, enabled = true }: UseWebRTCOptions): UseWe
5152 peerConnectionRef . current = null
5253 initializingRef . current = false
5354 pendingInitRef . current = false
55+ pendingCandidatesRef . current = [ ]
5456
5557 if ( pc ) {
5658 // Unsubscribe from WebSocket messages if available
@@ -84,11 +86,20 @@ export function useWebRTC({ entityId, enabled = true }: UseWebRTCOptions): UseWe
8486
8587 // Prevent multiple initializations
8688 if ( peerConnectionRef . current || initializingRef . current ) {
89+ // If we have an existing connection that's still active, don't reinitialize
90+ if (
91+ peerConnectionRef . current &&
92+ ( peerConnectionRef . current . connectionState === 'connected' ||
93+ peerConnectionRef . current . connectionState === 'connecting' )
94+ ) {
95+ return
96+ }
8797 return
8898 }
8999
90100 initializingRef . current = true
91101 setError ( null )
102+ pendingCandidatesRef . current = [ ]
92103
93104 try {
94105 // Create peer connection with STUN servers
@@ -114,9 +125,27 @@ export function useWebRTC({ entityId, enabled = true }: UseWebRTCOptions): UseWe
114125
115126 // Handle connection state changes
116127 pc . onconnectionstatechange = ( ) => {
117- if ( pc . connectionState === 'failed' || pc . connectionState === 'disconnected' ) {
118- setError ( 'Connection lost' )
119- setIsStreaming ( false )
128+ console . log ( `[WebRTC] Connection state changed to: ${ pc . connectionState } ` )
129+
130+ switch ( pc . connectionState ) {
131+ case 'failed' :
132+ setError ( 'Connection failed' )
133+ setIsStreaming ( false )
134+ // Clean up the connection
135+ cleanup ( )
136+ break
137+ case 'disconnected' :
138+ setError ( 'Connection lost' )
139+ setIsStreaming ( false )
140+ break
141+ case 'connected' :
142+ // Clear any previous errors when successfully connected
143+ setError ( null )
144+ break
145+ case 'closed' :
146+ // Connection was closed, ensure we're cleaned up
147+ setIsStreaming ( false )
148+ break
120149 }
121150 }
122151
@@ -166,18 +195,49 @@ export function useWebRTC({ entityId, enabled = true }: UseWebRTCOptions): UseWe
166195 if ( ! message . answer ) {
167196 return
168197 }
169- // Set the remote description
170- pc . setRemoteDescription ( { type : 'answer' , sdp : message . answer } ) . catch ( ( err ) => {
171- console . error ( '[WebRTC] Failed to set remote description:' , err )
172- setError ( 'Failed to set remote description' )
173- } )
198+ // Check if we're in the correct state to set remote description
199+ if ( pc . signalingState === 'have-local-offer' ) {
200+ // Set the remote description
201+ pc . setRemoteDescription ( { type : 'answer' , sdp : message . answer } )
202+ . then ( ( ) => {
203+ // Process any pending ICE candidates
204+ if ( pendingCandidatesRef . current . length > 0 ) {
205+ console . log (
206+ `[WebRTC] Processing ${ pendingCandidatesRef . current . length } pending ICE candidates`
207+ )
208+ pendingCandidatesRef . current . forEach ( ( candidate ) => {
209+ pc . addIceCandidate ( candidate ) . catch ( ( err ) =>
210+ console . error ( '[WebRTC] Failed to add pending ICE candidate:' , err )
211+ )
212+ } )
213+ pendingCandidatesRef . current = [ ]
214+ }
215+ } )
216+ . catch ( ( err ) => {
217+ console . error ( '[WebRTC] Failed to set remote description:' , err )
218+ setError ( 'Failed to set remote description' )
219+ } )
220+ } else {
221+ console . warn (
222+ `[WebRTC] Ignoring answer in wrong state: ${ pc . signalingState } . This may indicate duplicate messages or timing issues.`
223+ )
224+ }
174225 break
175226
176227 case 'candidate' :
177228 if ( message . candidate ) {
178- pc . addIceCandidate ( message . candidate ) . catch ( ( err ) =>
179- console . error ( '[WebRTC] Failed to add ICE candidate:' , err )
180- )
229+ // Only add ICE candidates if we have a remote description
230+ if ( pc . remoteDescription ) {
231+ pc . addIceCandidate ( message . candidate ) . catch ( ( err ) =>
232+ console . error ( '[WebRTC] Failed to add ICE candidate:' , err )
233+ )
234+ } else {
235+ // Queue the candidate to be added later when remote description is set
236+ pendingCandidatesRef . current . push ( message . candidate )
237+ console . log (
238+ `[WebRTC] Queuing ICE candidate (${ pendingCandidatesRef . current . length } pending)`
239+ )
240+ }
181241 }
182242 break
183243
0 commit comments