Skip to content

Sync upstream flutter/packages changes into main#1

Open
rwrz wants to merge 13 commits intomainfrom
dev
Open

Sync upstream flutter/packages changes into main#1
rwrz wants to merge 13 commits intomainfrom
dev

Conversation

@rwrz
Copy link

@rwrz rwrz commented Mar 11, 2026

Overview

This PR brings together all custom video_player enhancements developed on the dev branch, along with upstream flutter/packages sync. Below is a detailed breakdown of every custom commit.


1. Background Playback & Picture-in-Picture Support (b82df034f)

The foundational commit that adds background audio continuation and PiP across both platforms.

Android:

  • PlaybackService — a Media3 MediaSessionService that keeps audio playing when the app is backgrounded, with proper foreground service notification and media controls (play/pause/seek)
  • PipHandler — manages enterPictureInPictureMode() with aspect-ratio-aware params and auto-enter via setPictureInPictureParams
  • MediaBrowserService intent filter per Media3 docs for notification binding
  • Removed unnecessary POST_NOTIFICATIONS permission request (foreground service notifications are exempt)

iOS:

  • FVPBackgroundAudioHandler — activates AVAudioSession with .playback category, registers MPRemoteCommandCenter targets (play/pause/toggle/skip), and updates MPNowPlayingInfoCenter
  • FVPPipController — wraps AVPictureInPictureController with delegate callbacks that bridge PiP state changes back to Dart

Platform Interface:

  • New methods: setBackgroundPlaybackEnabled, setAutoEnterPip, startPip, stopPip, setMediaInfo
  • New events: pipChanged, backgroundPlaybackStateChanged
  • PlatformMediaInfo data class for title/artist/artworkUrl metadata

2. Code Simplification (c4130b04f)

Refactoring pass to reduce duplication introduced by the background/PiP commit:

  • Extract attachToActivity/detachFromActivity helpers in VideoPlayerPlugin.java (identical ActivityAware callbacks)
  • Extract removeBackgroundPlayer helper for the repeated remove-and-conditionally-unbind pattern (3 call sites)
  • Extract playerForId:error: helper in FVPVideoPlayerPlugin.m (5 identical player-lookup-or-error blocks)
  • Cache asset duration in FVPBackgroundAudioHandler to avoid re-querying every 1s tick
  • Remove redundant _backgroundEnabled state in example app — use controller.value.isPlayingInBackground directly

3. Auto-PiP Toggle in Example App (3fbc0cc31)

The setAutoEnterPip button now toggles between enable/disable instead of only enabling, making the example app more usable for testing PiP behavior.


4. Artwork Thumbnails in Notifications (9c11506a3)

Wires up the existing but previously unused artworkUrl field from PlatformMediaInfo to actually display artwork:

Android:

  • Sets MediaMetadata.artworkUri on the current MediaItem via replaceMediaItem(), letting Media3 auto-fetch and render it in the foreground service notification

iOS:

  • Downloads artwork asynchronously via NSURLSession, creates MPMediaItemArtwork, and includes it in MPNowPlayingInfoCenter for lock screen and Control Center display

5. Android PiP Events & Dismiss Detection (e94b1f5cb)

Full PiP event pipeline for Android:

  • PipCallbackHelper + VideoPlayerActivity for bridging onPictureInPictureModeChanged to Dart via pigeon event channel
  • Passes PiP window dimensions (screenWidthDp/screenHeightDp) from Configuration through PipStateEvent so Dart can size layouts without MediaQuery
  • pipSize field on VideoPlayerValue for PiP-aware layout decisions
  • Two-signal PiP dismiss detection: both lifecycle-paused + PiP-exit events must arrive (in any order) before pausing playback — prevents false positives when expanding back from PiP
  • Cleaned up dead BackgroundPlaybackEvent from pigeon and Dart handlers

6. iOS PiP & AVFoundation Updates (46eb9cc24)

  • Enhanced FVPPipController with additional delegate wiring and state management
  • Updated FVPTextureBasedVideoPlayer and FVPVideoPlayer for PiP layer integration
  • Extended pigeon API with iOS-specific PiP method
  • Updated example iOS project configuration (Info.plist background modes, Xcode project settings)
  • Cleaned up web example pubspec

7. Fix Android ANR on Dispose & PiP Lifecycle (df51f0f8a)

Critical stability fix:

  • ANR fix: Release MediaSession synchronously before ExoPlayer disposal to prevent queued media-button commands from posting to a dead Handler thread
  • PiP dismiss timer fallback for edge cases where the two-signal detection doesn't complete
  • Eager iOS PiP controller creation (don't wait for first PiP request)
  • iOS background audio suspension on manual PiP start
  • Cleaned up debug print statements

8. Fix Missing Import (16873e64b)

Adds the missing PipCallbackHelper import in VideoPlayerPlugin.java that was accidentally omitted from the PiP events commit.


9. Caching, ABR Quality Control & iOS Quality Events (dab73a0d0)

Video Caching:

  • VideoCacheManager (Android) — manages a SimpleCache with configurable max size for HLS/DASH segment caching via ExoPlayer's CacheDataSource

Adaptive Bitrate (ABR) Quality Control:

  • getAvailableQualities() — returns list of available video renditions (bitrate, width, height, codecs)
  • getCurrentQuality() — returns the currently selected/playing quality
  • setMaxBitrate(int) — caps the adaptive selector to a maximum bitrate
  • setMaxResolution(int width, int height) — caps the adaptive selector to a maximum resolution

iOS Quality Change Events:

  • FVPEventBridge observes AVPlayerItem access log notifications and emits qualityChanged events with bitrate/resolution info

Example App:

  • New HLS/ABR demo tab with quality list, current quality display, and bitrate/resolution cap controls

10. Network Error Recovery & ABR Muxed HLS Fix (c677f2007)

Configurable Network Error Recovery (Android):

  • AndroidVideoPlayerOptions with maxLoadRetries (segment-level retries) and maxPlayerRecoveryAttempts (player-level recovery after fatal errors)
  • Wired through platform interface → pigeon → native Android
  • ExoPlayerEventListener tracks recovery attempts, resets counter on READY state, surfaces error only after limit exceeded
  • DefaultLoadErrorHandlingPolicy configured on MediaSourceFactory for retry behavior
  • Removed ERROR_CODE_IO_BAD_HTTP_STATUS from transient error list (4xx/5xx are not transient)

ABR Quality Fix for Muxed HLS:

  • Accept TRACK_TYPE_DEFAULT (muxed HLS format) in addition to TRACK_TYPE_VIDEO in onDownstreamFormatChanged, checking for video dimensions to correctly report quality changes on muxed streams

11. Dart-Configurable Decoder Selection (Android) (8d553d79d)

Exposes video decoder enumeration and selection to Dart for handling problematic hardware decoders:

Use case: Some devices (notably Huawei/HiSilicon) have hardware decoders that pass initialization but crash at runtime during frame decoding. This API lets apps detect failures and fall back to software decoders.

Platform Interface:

  • VideoDecoderInfo (name, isHardwareAccelerated, isSoftwareOnly, isVendor)
  • VideoEventType.decoderChanged event
  • getAvailableDecoders(), getCurrentDecoderName(), setVideoDecoder() methods

Android Native:

  • ExoPlayer rebuild with custom MediaCodecSelector to force a specific decoder
  • State capture/restore (position, playback state) across rebuild
  • MediaCodecList enumeration with cached MIME type for decoder list availability across rebuilds

Example App:

  • New Decoders tab with decoder list, one-tap selection, and retry demo
  • DecoderRetrier best-practice class demonstrating active error monitoring during a settle period to catch runtime MediaCodec crashes (not just init failures)

Test Plan

  • Verify background audio playback on Android (notification controls, artwork)
  • Verify background audio playback on iOS (lock screen controls, artwork)
  • Test PiP enter/exit on Android (auto-enter and manual)
  • Test PiP enter/exit on iOS
  • Test PiP dismiss detection (swipe away PiP window should pause)
  • Verify no ANR on rapid dispose during background playback
  • Test HLS caching (play, seek back to cached segments)
  • Test ABR quality controls (set max bitrate/resolution, verify quality list)
  • Test ABR quality events on muxed HLS streams
  • Test network error recovery with maxLoadRetries and maxPlayerRecoveryAttempts
  • Test decoder enumeration and selection on Android
  • Test decoder fallback with DecoderRetrier on a device with known bad HW decoder

🤖 Generated with Claude Code

rwrz and others added 13 commits March 5, 2026 22:12
Add background audio playback and Picture-in-Picture support across
Android and iOS platforms.

Key changes:
- Add PlaybackService (Android) and FVPBackgroundAudioHandler (iOS) for
  background audio continuation with media notification controls
- Add PipHandler (Android) and FVPPipController (iOS) for PiP support
- Fix Android media notification by setting MediaSessionService intent
  action so onBind() returns the Media3 binder correctly
- Remove unnecessary POST_NOTIFICATIONS permission request (media
  notifications from foreground services are exempt)
- Update platform interface with background playback and PiP APIs
- Add MediaBrowserService intent filter per Media3 docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract attachToActivity/detachFromActivity helpers in
  VideoPlayerPlugin.java (identical ActivityAware callbacks)
- Extract removeBackgroundPlayer helper for repeated
  remove-and-conditionally-unbind pattern (3 call sites)
- Extract playerForId:error: helper in FVPVideoPlayerPlugin.m
  (5 identical player-lookup-or-error blocks)
- Cache asset duration in FVPBackgroundAudioHandler to avoid
  re-querying every 1s tick, add early return for nil currentItem
- Remove redundant _backgroundEnabled state in example app,
  use controller.value.isPlayingInBackground directly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The setAutoEnterPip button now toggles between enable/disable instead
of only enabling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…fications

Wire up the existing but unused artworkUrl field from PlatformMediaInfo
to actually display artwork in notifications on both platforms:

- Android: Set MediaMetadata.artworkUri on the current MediaItem via
  replaceMediaItem(), letting Media3 auto-fetch and render it in the
  foreground service notification.
- iOS: Download artwork asynchronously via NSURLSession, create
  MPMediaItemArtwork, and include it in MPNowPlayingInfoCenter for
  lock screen and Control Center display.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add PipCallbackHelper + VideoPlayerActivity for bridging Android
  onPictureInPictureModeChanged to Dart via pigeon event channel
- Pass PiP window dimensions (screenWidthDp/screenHeightDp) from
  Configuration through PipStateEvent for layout without MediaQuery
- Add pipSize field to VideoPlayerValue for PiP-aware layouts
- Implement two-signal PiP dismiss detection: lifecycle paused +
  PiP exit event must both arrive (in any order) before pausing,
  preventing false positives when expanding back from PiP
- Remove dead BackgroundPlaybackEvent from pigeon and Dart handlers
- Remove backgroundPlaybackStateChanged from VideoEventType enum

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
iOS/avfoundation PiP controller changes, pigeon regeneration,
example project config updates, and web example pubspec cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Release MediaSession synchronously before ExoPlayer disposal to prevent
queued media-button commands from posting to a dead Handler thread.
Also adds PiP dismiss timer fallback, eager iOS PiP controller creation,
iOS background suspension on manual PiP start, and cleans up debug prints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ge events

Adds video caching support via VideoCacheManager, adaptive bitrate
quality control methods (getAvailableQualities, getCurrentQuality,
setMaxBitrate, setMaxResolution), quality change event callbacks
on both Android and iOS, and an HLS/ABR demo tab in the example app.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ality events for muxed HLS

Network error recovery:
- Add AndroidVideoPlayerOptions with maxLoadRetries and
  maxPlayerRecoveryAttempts, configurable from Dart
- Wire through platform interface -> pigeon -> native Android
- ExoPlayerEventListener tracks recovery attempts, resets on READY,
  surfaces error after limit exceeded
- Configure DefaultLoadErrorHandlingPolicy on MediaSourceFactory
- Remove ERROR_CODE_IO_BAD_HTTP_STATUS from transient errors (4xx/5xx
  are not transient)

ABR quality fix:
- Accept TRACK_TYPE_DEFAULT (muxed HLS) in addition to TRACK_TYPE_VIDEO
  in onDownstreamFormatChanged, checking for video dimensions
- Remove debug logging from analytics listener

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expose decoder enumeration and selection to Dart so apps can query
available video decoders, force a specific decoder (e.g. software
fallback after HW decoder runtime crashes on Huawei/HiSilicon), and
persist known-good decoders per device.

- Platform interface: VideoDecoderInfo, VideoEventType.decoderChanged,
  getAvailableDecoders/getCurrentDecoderName/setVideoDecoder methods
- Android native: ExoPlayer rebuild with custom MediaCodecSelector,
  state capture/restore, MediaCodecList enumeration, cached MIME type
  for decoder list availability across rebuilds
- Pigeon: DecoderChangedEvent, PlatformVideoDecoder, 3 new API methods
- Dart plugin: Wire through AndroidVideoPlayer with duplicate init
  suppression and safe buffer polling during rebuild
- Example app: Decoders tab with decoder list, selection, retry demo
- Example: DecoderRetrier best-practice class with active error
  monitoring during settle period for runtime MediaCodec crashes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	packages/video_player/video_player/test/video_player_test.dart
@rwrz rwrz requested a review from marcelo-bottoni March 11, 2026 18:50
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