Skip to content

Release 2.12.0 - #1191

Draft
hiroshihorie wants to merge 1 commit into
mainfrom
release/2.12.0
Draft

Release 2.12.0#1191
hiroshihorie wants to merge 1 commit into
mainfrom
release/2.12.0

Conversation

@hiroshihorie

Copy link
Copy Markdown
Member

Minor release. Main theme is iOS audio robustness: the audio session is now resolved from engine state before any policy is pushed (fixes audio engine error -9001 in pre-connect / pre-join / playout-only flows), and microphone permission is requested before capture starts. Also raises the toolchain floor to Flutter 3.38 / Dart 3.10 for native assets, plus a batch of fixes in data channels, data streams, E2EE, token caching, and the Linux task runner.

Changes

Added

  • AudioSessionException for iOS audio session failures

Changed

  • Microphone permission and audio session failures now throw TrackCreateException / AudioSessionException instead of AudioProcessingException
  • Minimum supported versions raised to Flutter 3.38 / Dart 3.10 (floor for stable native assets)
  • json_annotation 4.12, serialization code regenerated with json_serializable 6.14

Fixed

  • BaseKeyProvider.create honors discardFrameWhenCryptorNotReady
  • Pre-connect audio buffer returns to a reusable state when recording fails to start
  • Subscriber data channel state events report the subscriber channel and correct reliability type, and no longer leak listeners
  • CachingTokenSource.fetch awaits its result so errors surface and the in-flight entry is cleared
  • sendText declares the UTF-8 byte length in the stream header (non-ASCII text streams were rejected)
  • Android: a failed local recording pre-warm no longer aborts microphone capture
  • iOS: audio session configured from engine state before a policy is pushed (audio engine error -9001)
  • iOS/macOS: microphone permission requested before capture starts, failing fast with TrackCreateException while the app is not in the foreground
  • Linux: use-after-free in TaskRunnerLinux::EnqueueTask when the runner is destroyed before dispatch

Release review

Diff reviewed against v2.11.0 (11 commits). flutter analyze, dart format, import_sorter, check_version, and flutter test (407 tests) all pass locally. Version fields agree across .version, pubspec.yaml, README.md, lib/src/livekit.dart, and both podspecs; .changes/ is empty; the 13 changelog bullets match the consumed changesets. flutter_webrtc pin unchanged at 1.6.0.

The 111-file commit (#1170) is confirmed behavior-neutral after stripping whitespace and trailing commas, with one intentional rewrite: room.dart now uses null-aware map elements (?localParticipant?.sid), verified equivalent. Regenerated *.g.dart keep the same nullability and null-omission semantics.

No blockers. Items worth a look before tagging (none require holding the release):

  • iOS permission gate uses applicationState == .active (shared_swift/LiveKitPlugin.swift handleEnsureMicrophoneAccess). .inactive also covers a visible iPad Split View app and the launch window before didBecomeActive, so a first-run withPreConnectAudio from initState throws TrackCreateException instead of prompting. != .background would avoid the false positive. The behavior is documented on withPreConnectAudio, so this is a judgment call.
  • Default recording preset now applies whenever nothing was pushed in automatic mode (defaultRecordingConfigurationLocked). This is the intended -9001 fix, but apps that configure AVAudioSession themselves and start the engine before Dart syncs (CallKit wake) now get LiveKit's preset unless they opt into manual mode. Worth a louder changelog / migration note.
  • Android pre-warm swallow is broad (LiveKitPlugin.kt handleStartLocalRecording). prewarmRecording applies the processing options first; if that step throws, the options are silently not applied and Dart still sees success. Narrowing the catch to the recorder-prep stage would keep noProcessing() failures visible.
  • Exception type change shipped as a patch changeset. AudioProcessingException is @experimental and does not extend LiveKitException, so existing on AudioProcessingException catch sites (the pattern in doc/audio.md) will now miss permission / -9001 failures. Fine for a minor release, but the changelog entry could call this out.
  • withPreConnectAudio calls startRecording outside its try, so a permission failure both fires onError and propagates the exception to the caller.
  • On every mic unmute, startCapture re-pushes the audio session policy; with the engine already running this re-applies the same playout config that didDisableEngine already resolved on mute. Redundant but harmless.
  • ReusableCompleter.completeError drops the error when nothing is listening yet, so a caller that reads agentReadyFuture only after startRecording throws gets a fresh, never-completing future. Pre-existing, but the new preconnect failure paths make it easier to hit.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Warning

No changeset found

If this PR includes user-facing changes, please add a changeset file in .changes/

Format: level type="kind" "description"

patch type="fixed" "Fix audio frame generation"
minor type="added" "Add support for custom audio processing"
major type="changed" "Breaking: Rename Room.connect() to Room.join()"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant