[bug] Full reconnect: a rePublishAllTracks() failure escapes the EngineRestartedEvent handler and RoomReconnectedEvent is never emitted

オープン
#1,274 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 2 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
64/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
dart, flutter

調査の方向性

Start in Room._setUpEngineListeners in livekit_client/src/core/room.dart and trace the EngineRestartedEvent handler through rePublishAllTracks() in livekit_client/src/participant/local.dart. Compare the expected failure handling with the cited handleRestarted behavior in client-sdk-js. Done means a republish failure does not prevent reconnect completion, and muted stopped tracks do not trigger the reported failure.

索引モデルが issue の本文から書いたものです。

説明

Describe the bug

In Room._setUpEngineListeners, the EngineRestartedEvent handler awaits rePublishAllTracks() without a try/catch:

..on<EngineRestartedEvent>((event) async {
  // re-publish all tracks
  await localParticipant?.rePublishAllTracks();
  for (var participant in _remoteParticipants.toList()) { /* sendUpdateTrackSettings() */ }
  events.emit(const RoomReconnectedEvent());
  notifyListeners();
})

If republishing throws, the error escapes the listener as an unhandled async error and the rest of the handler is skipped: remote track settings are not re-sent, RoomReconnectedEvent is never emitted and listeners are not notified. RoomConnectedEvent is still emitted from the join response, so apps that only wait for RoomReconnectedEvent stay in a "reconnecting" state.

We see two variants in production (Crashlytics). In both, the local microphone had been muted with setMicrophoneEnabled(false) (default stopAudioCaptureOnMute: true) before the full reconnect.

Android 16:

Unable to RTCPeerConnection::addTransceiver: addTransceiver(): track is null
#0 RTCPeerConnectionNative.addTransceiver (flutter_webrtc/src/native/rtc_peerconnection_impl.dart:650)
#1 EngineInternalMethods.createTransceiverRTCRtpSender (livekit_client/src/core/engine.dart:1682)
#2 LocalParticipant._publishAudioTrack.negotiate (livekit_client/src/participant/local.dart:203)
#4 LocalParticipant._publishAudioTrack (livekit_client/src/participant/local.dart:210)
#5 SerialRunner.run (livekit_client/src/support/serial_runner.dart:45)
#6 LocalParticipant.publishAudioTrack (livekit_client/src/participant/local.dart:160)
#7 LocalParticipant.rePublishAllTracks (livekit_client/src/participant/local.dart:650)
#8 Room._setUpEngineListeners.<anonymous closure> (livekit_client/src/core/room.dart:622)

iOS 27.0.1 (after audio session interruptions):

LiveKit Exception: [AudioSessionException] Failed to configure the audio session (audio engine error -4100)
#0 LocalAudioTrack.startCapture (livekit_client/src/track/local/audio.dart:104)
#1 Track.start (livekit_client/src/track/track.dart:113)
#2 LocalParticipant._publishAudioTrack (livekit_client/src/participant/local.dart:182)
#3 SerialRunner.run (livekit_client/src/support/serial_runner.dart:45)
#4 LocalParticipant.publishAudioTrack (livekit_client/src/participant/local.dart:160)
#5 LocalParticipant.rePublishAllTracks (livekit_client/src/participant/local.dart:650)
#6 Room._setUpEngineListeners.<anonymous closure> (livekit_client/src/core/room.dart:622)

To Reproduce

  1. Connect, enable the microphone, then disable it with setMicrophoneEnabled(false).
  2. Force a full reconnect: kill the server (kill -9 on a local livekit-server --dev) and start it again within a few seconds.
  3. On Android, rePublishAllTracks() throws "track is null", the exception is unhandled and RoomReconnectedEvent is not emitted.

Reproduced on an Android emulator (API 37) against livekit-server 1.13.11. With the microphone enabled during the reconnect there is no error.

Expected behavior

The same as handleRestarted in client-sdk-js (src/room/CoreRoom.ts), where a republish failure is logged and the reconnect still completes:

try {
  await this.localParticipant.republishAllTracks(undefined, true);
} catch (error) {
  this.log.error('error trying to re-publish tracks after reconnection', { error });
}
// ...
this.emit(RoomEvent.Reconnected);

Also, client-sdk-js does not restart muted tracks before republishing (!track.isMuted), while publishAudioTrack always calls track.start(). That call is what fails for the muted, stopped track in both variants above.

Platform information

  • Flutter version: 3.47.8 (stable)
  • Plugin version: livekit_client 2.13.2 (the same handler is on main as of 2026-11-02), flutter_webrtc 1.6.3
  • Flutter target OS: Android (emulator and real devices), iOS (real devices)
  • Flutter target OS version: Android 16 and API 37 emulator, iOS 27.0.1
  • Flutter console log: stack traces above
主要言語
Dart
スター
421
フォーク
260
平均マージ
2日 8時間
マージ済み PR(30日)
25

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

livekit/client-sdk-flutter のほかの issue

livekit/client-sdk-flutter の issue をすべて見る

似ている issue

Dart の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。