@@ -120,6 +120,9 @@ class RTCSession extends EventManager implements Owner {
120
120
// Flag to indicate PeerConnection ready for actions.
121
121
bool _rtcReady = true ;
122
122
123
+ Timer ? _iceDisconnectTimer;
124
+ bool _isAttemptingIceRestart = false ;
125
+
123
126
// SIP Timers.
124
127
final SIPTimers _timers = SIPTimers ();
125
128
@@ -1548,6 +1551,8 @@ class RTCSession extends EventManager implements Owner {
1548
1551
clearTimeout (_timers.invite2xxTimer);
1549
1552
clearTimeout (_timers.userNoAnswerTimer);
1550
1553
1554
+ _iceDisconnectTimer? .cancel ();
1555
+
1551
1556
// Clear Session Timers.
1552
1557
clearTimeout (_sessionTimers.timer);
1553
1558
@@ -1635,20 +1640,79 @@ class RTCSession extends EventManager implements Owner {
1635
1640
Map <String , dynamic > rtcConstraints) async {
1636
1641
_connection = await createPeerConnection (pcConfig, rtcConstraints);
1637
1642
_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
+
1639
1651
if (state == RTCIceConnectionState .RTCIceConnectionStateFailed ) {
1652
+ logger.e ('ICE Connection State Failed.' );
1653
+ _iceDisconnectTimer? .cancel ();
1640
1654
terminate (< String , dynamic > {
1641
1655
'cause' : DartSIP_C .CausesType .RTP_TIMEOUT ,
1642
1656
'status_code' : 408 ,
1643
- 'reason_phrase' : DartSIP_C . CausesType . RTP_TIMEOUT
1657
+ 'reason_phrase' : 'ICE Connection Failed'
1644
1658
});
1645
1659
} else if (state ==
1646
1660
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
1649
1714
}
1650
1715
};
1651
-
1652
1716
// In future versions, unified-plan will be used by default
1653
1717
String ? sdpSemantics = 'unified-plan' ;
1654
1718
if (pcConfig['sdpSemantics' ] != null ) {
0 commit comments