From 046bbb482bd2546ddc8ca41c8db87d22d3167a02 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 04:34:17 +0900 Subject: [PATCH 1/8] fix imports --- example/lib/widgets/controls.dart | 2 +- lib/src/agent/agent.dart | 2 +- lib/src/agent/chat/message.dart | 2 +- lib/src/core/engine.dart | 3 ++- lib/src/core/room.dart | 3 +-- lib/src/core/signal_client.dart | 2 +- lib/src/e2ee/e2ee_manager.dart | 4 +++- lib/src/managers/broadcast_manager.dart | 2 +- lib/src/participant/local.dart | 3 ++- lib/src/stats/stats.dart | 2 +- lib/src/support/disposable.dart | 4 +++- lib/src/support/platform/io.dart | 2 +- lib/src/support/platform/web.dart | 2 +- lib/src/track/local/local.dart | 2 +- lib/src/track/local/video.dart | 3 ++- lib/src/track/track.dart | 2 +- lib/src/types/transcription_segment.dart | 2 +- lib/src/utils.dart | 3 ++- lib/src/widgets/screen_select_dialog.dart | 3 ++- lib/src/widgets/video_track_renderer.dart | 2 +- 20 files changed, 29 insertions(+), 21 deletions(-) diff --git a/example/lib/widgets/controls.dart b/example/lib/widgets/controls.dart index e022364b7..fbe8c815e 100644 --- a/example/lib/widgets/controls.dart +++ b/example/lib/widgets/controls.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:collection/collection.dart'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_background/flutter_background.dart'; import 'package:livekit_client/livekit_client.dart'; diff --git a/lib/src/agent/agent.dart b/lib/src/agent/agent.dart index 4c2ff5bcd..e230829fb 100644 --- a/lib/src/agent/agent.dart +++ b/lib/src/agent/agent.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show ChangeNotifier; import 'package:collection/collection.dart'; diff --git a/lib/src/agent/chat/message.dart b/lib/src/agent/chat/message.dart index b744fee25..0a01a3743 100644 --- a/lib/src/agent/chat/message.dart +++ b/lib/src/agent/chat/message.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart'; /// A message received from the agent. @immutable diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index 37e846570..e667659d2 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -15,8 +15,9 @@ // ignore_for_file: deprecated_member_use_from_same_package import 'dart:async'; +import 'dart:typed_data' show Uint8List; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kDebugMode, kIsWeb; import 'package:collection/collection.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index 2508063f8..77ede0fb5 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -13,8 +13,7 @@ // limitations under the License. import 'dart:async'; - -import 'package:flutter/foundation.dart' hide internal; +import 'dart:typed_data' show Uint8List; import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; diff --git a/lib/src/core/signal_client.dart b/lib/src/core/signal_client.dart index 3145ddfca..47ce08832 100644 --- a/lib/src/core/signal_client.dart +++ b/lib/src/core/signal_client.dart @@ -15,7 +15,7 @@ import 'dart:async'; import 'dart:collection'; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fixnum/fixnum.dart'; diff --git a/lib/src/e2ee/e2ee_manager.dart b/lib/src/e2ee/e2ee_manager.dart index b9278d09d..3241a4e81 100644 --- a/lib/src/e2ee/e2ee_manager.dart +++ b/lib/src/e2ee/e2ee_manager.dart @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'dart:typed_data' show Uint8List; + +import 'package:flutter/foundation.dart' show kDebugMode, kIsWeb; import 'package:flutter_webrtc/flutter_webrtc.dart'; diff --git a/lib/src/managers/broadcast_manager.dart b/lib/src/managers/broadcast_manager.dart index 8d92bb3d1..e42e8eea4 100644 --- a/lib/src/managers/broadcast_manager.dart +++ b/lib/src/managers/broadcast_manager.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show ChangeNotifier; import 'package:meta/meta.dart'; diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index 62978adcb..432c7883f 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -17,8 +17,9 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; +import 'dart:typed_data' show Uint8List; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:async/async.dart'; import 'package:fixnum/fixnum.dart'; diff --git a/lib/src/stats/stats.dart b/lib/src/stats/stats.dart index a38898467..f75d9ac58 100644 --- a/lib/src/stats/stats.dart +++ b/lib/src/stats/stats.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'audio_source_stats.dart'; diff --git a/lib/src/support/disposable.dart b/lib/src/support/disposable.dart index 5d1ebeb5e..70d77015e 100644 --- a/lib/src/support/disposable.dart +++ b/lib/src/support/disposable.dart @@ -14,7 +14,9 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show ChangeNotifier, VoidCallback; + +import 'package:meta/meta.dart'; import '../extensions.dart'; import '../logger.dart'; diff --git a/lib/src/support/platform/io.dart b/lib/src/support/platform/io.dart index 2a2afa556..af31ba351 100644 --- a/lib/src/support/platform/io.dart +++ b/lib/src/support/platform/io.dart @@ -14,7 +14,7 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb, kIsWasm; import '../platform.dart'; diff --git a/lib/src/support/platform/web.dart b/lib/src/support/platform/web.dart index f5316dfa0..7fa7f774b 100644 --- a/lib/src/support/platform/web.dart +++ b/lib/src/support/platform/web.dart @@ -15,7 +15,7 @@ import 'dart:js_interop'; import 'dart:js_interop_unsafe'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show defaultTargetPlatform, TargetPlatform; import 'package:web/web.dart' as web; diff --git a/lib/src/track/local/local.dart b/lib/src/track/local/local.dart index 981b0717d..2ce82883b 100644 --- a/lib/src/track/local/local.dart +++ b/lib/src/track/local/local.dart @@ -14,7 +14,7 @@ import 'dart:async'; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; diff --git a/lib/src/track/local/video.dart b/lib/src/track/local/video.dart index 9b8e66b28..b16388895 100644 --- a/lib/src/track/local/video.dart +++ b/lib/src/track/local/video.dart @@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:collection/collection.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; +import 'package:meta/meta.dart'; import '../../events.dart'; import '../../exceptions.dart'; diff --git a/lib/src/track/track.dart b/lib/src/track/track.dart index 3c0f09170..92dffc66e 100644 --- a/lib/src/track/track.dart +++ b/lib/src/track/track.dart @@ -14,7 +14,7 @@ import 'dart:async'; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; import 'package:meta/meta.dart'; diff --git a/lib/src/types/transcription_segment.dart b/lib/src/types/transcription_segment.dart index 37d61aded..0b2b5d0f0 100644 --- a/lib/src/types/transcription_segment.dart +++ b/lib/src/types/transcription_segment.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart'; @immutable class TranscriptionSegment { diff --git a/lib/src/utils.dart b/lib/src/utils.dart index d242e6d90..aa8259ea3 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -15,8 +15,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math' as math; +import 'dart:typed_data' show Uint8List; -import 'package:flutter/foundation.dart' hide internal; +import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform; import 'package:collection/collection.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; diff --git a/lib/src/widgets/screen_select_dialog.dart b/lib/src/widgets/screen_select_dialog.dart index 16af8b34b..69a69136a 100644 --- a/lib/src/widgets/screen_select_dialog.dart +++ b/lib/src/widgets/screen_select_dialog.dart @@ -13,8 +13,9 @@ // limitations under the License. import 'dart:async'; +import 'dart:typed_data' show Uint8List; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; diff --git a/lib/src/widgets/video_track_renderer.dart b/lib/src/widgets/video_track_renderer.dart index 06f8817bd..95b683bce 100644 --- a/lib/src/widgets/video_track_renderer.dart +++ b/lib/src/widgets/video_track_renderer.dart @@ -15,7 +15,7 @@ import 'dart:async'; import 'dart:math'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc; From 60f04f78a619305a48d6d3023095cfaa6d0652ab Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 04:39:18 +0900 Subject: [PATCH 2/8] Create fix-imports --- .changes/fix-imports | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changes/fix-imports diff --git a/.changes/fix-imports b/.changes/fix-imports new file mode 100644 index 000000000..929483765 --- /dev/null +++ b/.changes/fix-imports @@ -0,0 +1 @@ +patch type="fixed" "Use explicit show clauses for foundation imports" From 35d61e4f37d784cf59ebed02fe9575165e976988 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 04:54:47 +0900 Subject: [PATCH 3/8] v13 --- lib/src/core/engine.dart | 7 +++++++ lib/src/extensions.dart | 1 + lib/src/options.dart | 2 +- lib/src/types/other.dart | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index e667659d2..8a6848f22 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -1372,9 +1372,16 @@ class Engine extends Disposable with EventsEmittable { await handleReconnect(ClientDisconnectReason.leaveReconnect); break; case lk_rtc.LeaveRequest_Action.RESUME: + fullReconnectOnNext = false; // reconnect immediately instead of waiting for next attempt await handleReconnect(ClientDisconnectReason.leaveReconnect); + break; default: + // Fallback for protocol version < 13: check canReconnect field + if (event.canReconnect) { + fullReconnectOnNext = true; + await handleReconnect(ClientDisconnectReason.leaveReconnect); + } break; } }); diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index d919da94b..a5d43d7f3 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -66,6 +66,7 @@ extension ProtocolVersionExt on ProtocolVersion { ProtocolVersion.v10: '10', ProtocolVersion.v11: '11', ProtocolVersion.v12: '12', + ProtocolVersion.v13: '13', }[this]!; } diff --git a/lib/src/options.dart b/lib/src/options.dart index af31ce5fd..a18f53a60 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -64,7 +64,7 @@ class ConnectOptions { const ConnectOptions({ this.autoSubscribe = true, this.rtcConfiguration = const RTCConfiguration(), - this.protocolVersion = ProtocolVersion.v12, + this.protocolVersion = ProtocolVersion.v13, this.timeouts = Timeouts.defaultTimeouts, }); } diff --git a/lib/src/types/other.dart b/lib/src/types/other.dart index 46f39b07b..35e1cd13d 100644 --- a/lib/src/types/other.dart +++ b/lib/src/types/other.dart @@ -35,6 +35,7 @@ enum ProtocolVersion { v10, v11, v12, + v13, // Regions in leave request, canReconnect obsoleted by action } /// Connection state type used throughout the SDK. From 3c724efa7010ec68e89cfc4efbc162453fd4d9f9 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:32:03 +0900 Subject: [PATCH 4/8] update leave request --- lib/src/core/signal_client.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/core/signal_client.dart b/lib/src/core/signal_client.dart index 47ce08832..388b40964 100644 --- a/lib/src/core/signal_client.dart +++ b/lib/src/core/signal_client.dart @@ -199,7 +199,11 @@ class SignalClient extends Disposable with EventsEmittable { Future sendLeave() async { _sendRequest(lk_rtc.SignalRequest( - leave: lk_rtc.LeaveRequest(canReconnect: false, reason: lk_models.DisconnectReason.CLIENT_INITIATED))); + leave: lk_rtc.LeaveRequest( + reason: lk_models.DisconnectReason.CLIENT_INITIATED, + // server doesn't process this field, keeping it here to indicate the intent of a full disconnect + action: lk_rtc.LeaveRequest_Action.DISCONNECT, + ))); } // resets internal state to a re-usable state From d18d855417ae000b1bc191ac42a6cb88a016ffaf Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:52:59 +0900 Subject: [PATCH 5/8] update leave action --- lib/src/core/engine.dart | 47 ++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index 8a6848f22..8271c049c 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -1355,34 +1355,25 @@ class Engine extends Disposable with EventsEmittable { logger.fine('updating regions'); _regionUrlProvider?.setServerReportedRegions(event.regions!); } - switch (event.action) { - case lk_rtc.LeaveRequest_Action.DISCONNECT: - if (connectionState == ConnectionState.reconnecting) { - logger.warning('[Signal] Received Leave while engine is reconnecting, ignoring...'); - return; - } - await signalClient.cleanUp(); - fullReconnectOnNext = false; - await disconnect(); - events.emit(EngineDisconnectedEvent(reason: event.reason.toSDKType())); - break; - case lk_rtc.LeaveRequest_Action.RECONNECT: - fullReconnectOnNext = true; - // reconnect immediately instead of waiting for next attempt - await handleReconnect(ClientDisconnectReason.leaveReconnect); - break; - case lk_rtc.LeaveRequest_Action.RESUME: - fullReconnectOnNext = false; - // reconnect immediately instead of waiting for next attempt - await handleReconnect(ClientDisconnectReason.leaveReconnect); - break; - default: - // Fallback for protocol version < 13: check canReconnect field - if (event.canReconnect) { - fullReconnectOnNext = true; - await handleReconnect(ClientDisconnectReason.leaveReconnect); - } - break; + if (event.action == lk_rtc.LeaveRequest_Action.RESUME) { + fullReconnectOnNext = false; + // reconnect immediately instead of waiting for next attempt + await handleReconnect(ClientDisconnectReason.leaveReconnect); + } else if (event.action == lk_rtc.LeaveRequest_Action.RECONNECT || + // canReconnect is deprecated in protocol version >= 13 + event.canReconnect) { + fullReconnectOnNext = true; + // reconnect immediately instead of waiting for next attempt + await handleReconnect(ClientDisconnectReason.leaveReconnect); + } else { + if (connectionState == ConnectionState.reconnecting) { + logger.warning('[Signal] Received Leave while engine is reconnecting, ignoring...'); + return; + } + await signalClient.cleanUp(); + fullReconnectOnNext = false; + await disconnect(); + events.emit(EngineDisconnectedEvent(reason: event.reason.toSDKType())); } }); From 6f50e9f8ab004587ab9f985e6758cbdcfd523825 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:54:04 +0900 Subject: [PATCH 6/8] changes --- .changes/protocol-v13 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changes/protocol-v13 diff --git a/.changes/protocol-v13 b/.changes/protocol-v13 new file mode 100644 index 000000000..3f973f1d9 --- /dev/null +++ b/.changes/protocol-v13 @@ -0,0 +1 @@ +minor type="feature" "Support protocol v13 with LeaveRequest action" From 2e066c945066ae386f28762aa61f02bf0f631e8c Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:59:20 +0900 Subject: [PATCH 7/8] comments and log --- lib/src/core/engine.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index 8271c049c..3babe5123 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -1351,21 +1351,25 @@ class Engine extends Disposable with EventsEmittable { token = event.token; }) ..on((event) async { + logger.fine('[Signal] Leave received, action: ${event.action}, reason: ${event.reason}'); if (event.regions != null && _regionUrlProvider != null) { logger.fine('updating regions'); _regionUrlProvider?.setServerReportedRegions(event.regions!); } + // Protocol v13: LeaveRequest.action replaces the deprecated canReconnect boolean. + // canReconnect is still checked for backward compatibility with v12 servers + // (where action defaults to DISCONNECT=0 since it's unset). if (event.action == lk_rtc.LeaveRequest_Action.RESUME) { fullReconnectOnNext = false; // reconnect immediately instead of waiting for next attempt await handleReconnect(ClientDisconnectReason.leaveReconnect); } else if (event.action == lk_rtc.LeaveRequest_Action.RECONNECT || - // canReconnect is deprecated in protocol version >= 13 event.canReconnect) { fullReconnectOnNext = true; // reconnect immediately instead of waiting for next attempt await handleReconnect(ClientDisconnectReason.leaveReconnect); } else { + // DISCONNECT or v12 server with canReconnect=false if (connectionState == ConnectionState.reconnecting) { logger.warning('[Signal] Received Leave while engine is reconnecting, ignoring...'); return; From 5f42b4985ea9e1c23435b23cc3c15b473695ca14 Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:01:04 +0900 Subject: [PATCH 8/8] format --- lib/src/core/engine.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index 3babe5123..570e3101e 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -1363,8 +1363,7 @@ class Engine extends Disposable with EventsEmittable { fullReconnectOnNext = false; // reconnect immediately instead of waiting for next attempt await handleReconnect(ClientDisconnectReason.leaveReconnect); - } else if (event.action == lk_rtc.LeaveRequest_Action.RECONNECT || - event.canReconnect) { + } else if (event.action == lk_rtc.LeaveRequest_Action.RECONNECT || event.canReconnect) { fullReconnectOnNext = true; // reconnect immediately instead of waiting for next attempt await handleReconnect(ClientDisconnectReason.leaveReconnect);