@@ -120,6 +120,9 @@ class RTCSession extends EventManager implements Owner {
120120 // Flag to indicate PeerConnection ready for actions.
121121 bool _rtcReady = true ;
122122
123+ Timer ? _iceDisconnectTimer;
124+ bool _isAttemptingIceRestart = false ;
125+
123126 // SIP Timers.
124127 final SIPTimers _timers = SIPTimers ();
125128
@@ -1548,6 +1551,8 @@ class RTCSession extends EventManager implements Owner {
15481551 clearTimeout (_timers.invite2xxTimer);
15491552 clearTimeout (_timers.userNoAnswerTimer);
15501553
1554+ _iceDisconnectTimer? .cancel ();
1555+
15511556 // Clear Session Timers.
15521557 clearTimeout (_sessionTimers.timer);
15531558
@@ -1635,20 +1640,79 @@ class RTCSession extends EventManager implements Owner {
16351640 Map <String , dynamic > rtcConstraints) async {
16361641 _connection = await createPeerConnection (pcConfig, rtcConstraints);
16371642 _connection! .onIceConnectionState = (RTCIceConnectionState state) {
1638- // TODO(cloudwebrtc): Do more with different states.
1643+ if (_state == RtcSessionState .terminated ||
1644+ _state == RtcSessionState .canceled) {
1645+ logger.d (
1646+ 'ICE State change ignored, SIP session already terminated/canceled.' );
1647+ _iceDisconnectTimer? .cancel ();
1648+ return ;
1649+ }
1650+
16391651 if (state == RTCIceConnectionState .RTCIceConnectionStateFailed ) {
1652+ logger.e ('ICE Connection State Failed.' );
1653+ _iceDisconnectTimer? .cancel ();
16401654 terminate (< String , dynamic > {
16411655 'cause' : DartSIP_C .CausesType .RTP_TIMEOUT ,
16421656 'status_code' : 408 ,
1643- 'reason_phrase' : DartSIP_C . CausesType . RTP_TIMEOUT
1657+ 'reason_phrase' : 'ICE Connection Failed'
16441658 });
16451659 } else if (state ==
16461660 RTCIceConnectionState .RTCIceConnectionStateDisconnected ) {
1647- if (_state == RtcSessionState .terminated) return ;
1648- _iceRestart ();
1661+ logger.w ('ICE Connection State Disconnected.' );
1662+ if (_iceDisconnectTimer == null && ! _isAttemptingIceRestart) {
1663+ logger.i ('Starting ICE disconnect timer...' );
1664+ _iceDisconnectTimer = Timer (const Duration (seconds: 20 ), () {
1665+ logger.w ('ICE disconnect timer fired!' );
1666+ if (_connection? .iceConnectionState ==
1667+ RTCIceConnectionState .RTCIceConnectionStateDisconnected &&
1668+ _state != RtcSessionState .terminated &&
1669+ _state != RtcSessionState .canceled &&
1670+ ! _isAttemptingIceRestart) {
1671+ logger.i ('Attempting ICE restart after timeout...' );
1672+ _isAttemptingIceRestart = true ;
1673+ _iceRestart ();
1674+ } else {
1675+ logger.i ('ICE restart aborted (state changed during timer).' );
1676+ }
1677+ _iceDisconnectTimer = null ;
1678+ });
1679+ } else {
1680+ logger.d (
1681+ 'ICE disconnect timer not started (already running or attempting restart).' );
1682+ }
1683+ } else if (state ==
1684+ RTCIceConnectionState .RTCIceConnectionStateConnected ||
1685+ state == RTCIceConnectionState .RTCIceConnectionStateCompleted ) {
1686+ // If connection recovers, cancel timer and reset flag
1687+ if (_iceDisconnectTimer != null || _isAttemptingIceRestart) {
1688+ logger.i (
1689+ 'ICE Connection State Connected/Completed. Canceling timer/resetting flag.' );
1690+ _iceDisconnectTimer? .cancel ();
1691+ _isAttemptingIceRestart = false ;
1692+ } else {
1693+ logger.i ('ICE Connection State Connected/Completed.' );
1694+ }
1695+ } else if (state == RTCIceConnectionState .RTCIceConnectionStateClosed ) {
1696+ // Connection closed locally, usually via _connection.close() called by terminate()
1697+ logger.i ('ICE Connection State Closed.' ); // Use logger.i
1698+ _iceDisconnectTimer? .cancel (); // Ensure timer is cancelled
1699+ // Ensure *SIP* session state reflects closure if not already set by terminate()
1700+ if (_state != RtcSessionState .terminated &&
1701+ _state != RtcSessionState .canceled) {
1702+ logger.w (
1703+ 'ICE closed but SIP session state was not terminal. Terminating SIP session now.' );
1704+ terminate (< String , dynamic > {
1705+ 'cause' : DartSIP_C .CausesType .WEBRTC_ERROR ,
1706+ 'status_code' : 487 ,
1707+ 'reason_phrase' : 'ICE Connection Closed'
1708+ });
1709+ }
1710+ } else if (state == RTCIceConnectionState .RTCIceConnectionStateChecking ) {
1711+ logger.d ('ICE Connection State Checking...' ); // Use logger.d
1712+ } else if (state == RTCIceConnectionState .RTCIceConnectionStateNew ) {
1713+ logger.d ('ICE Connection State New.' ); // Use logger.d
16491714 }
16501715 };
1651-
16521716 // In future versions, unified-plan will be used by default
16531717 String ? sdpSemantics = 'unified-plan' ;
16541718 if (pcConfig['sdpSemantics' ] != null ) {
0 commit comments