Skip to content

Commit 356e5d7

Browse files
author
Mikael Wills
committed
Handling of ice states and network dropout timer
1 parent a31fc33 commit 356e5d7

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ dependencies:
2626
path: ../
2727
shared_preferences: ^2.2.0
2828
permission_handler: ^11.1.0
29-
flutter_webrtc: ^0.12.6
29+
flutter_webrtc: ^0.12.7
3030
provider: 6.1.2
3131
logger: ^2.5.0
3232

lib/src/rtc_session.dart

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies:
1010
bloc: ^9.0.0
1111
collection: ^1.18.0
1212
crypto: ^3.0.3
13-
flutter_webrtc: ^0.12.6
13+
flutter_webrtc: ^0.12.7
1414
intl: ^0.20.1
1515
logger: ^2.0.2+1
1616
path: ^1.6.4

0 commit comments

Comments
 (0)