Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR brings together all custom
video_playerenhancements developed on thedevbranch, along with upstreamflutter/packagessync. 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 Media3MediaSessionServicethat keeps audio playing when the app is backgrounded, with proper foreground service notification and media controls (play/pause/seek)PipHandler— managesenterPictureInPictureMode()with aspect-ratio-aware params and auto-enter viasetPictureInPictureParamsMediaBrowserServiceintent filter per Media3 docs for notification bindingPOST_NOTIFICATIONSpermission request (foreground service notifications are exempt)iOS:
FVPBackgroundAudioHandler— activatesAVAudioSessionwith.playbackcategory, registersMPRemoteCommandCentertargets (play/pause/toggle/skip), and updatesMPNowPlayingInfoCenterFVPPipController— wrapsAVPictureInPictureControllerwith delegate callbacks that bridge PiP state changes back to DartPlatform Interface:
setBackgroundPlaybackEnabled,setAutoEnterPip,startPip,stopPip,setMediaInfopipChanged,backgroundPlaybackStateChangedPlatformMediaInfodata class for title/artist/artworkUrl metadata2. Code Simplification (
c4130b04f)Refactoring pass to reduce duplication introduced by the background/PiP commit:
attachToActivity/detachFromActivityhelpers inVideoPlayerPlugin.java(identicalActivityAwarecallbacks)removeBackgroundPlayerhelper for the repeated remove-and-conditionally-unbind pattern (3 call sites)playerForId:error:helper inFVPVideoPlayerPlugin.m(5 identical player-lookup-or-error blocks)FVPBackgroundAudioHandlerto avoid re-querying every 1s tick_backgroundEnabledstate in example app — usecontroller.value.isPlayingInBackgrounddirectly3. Auto-PiP Toggle in Example App (
3fbc0cc31)The
setAutoEnterPipbutton 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
artworkUrlfield fromPlatformMediaInfoto actually display artwork:Android:
MediaMetadata.artworkUrion the currentMediaItemviareplaceMediaItem(), letting Media3 auto-fetch and render it in the foreground service notificationiOS:
NSURLSession, createsMPMediaItemArtwork, and includes it inMPNowPlayingInfoCenterfor lock screen and Control Center display5. Android PiP Events & Dismiss Detection (
e94b1f5cb)Full PiP event pipeline for Android:
PipCallbackHelper+VideoPlayerActivityfor bridgingonPictureInPictureModeChangedto Dart via pigeon event channelscreenWidthDp/screenHeightDp) fromConfigurationthroughPipStateEventso Dart can size layouts withoutMediaQuerypipSizefield onVideoPlayerValuefor PiP-aware layout decisionsBackgroundPlaybackEventfrom pigeon and Dart handlers6. iOS PiP & AVFoundation Updates (
46eb9cc24)FVPPipControllerwith additional delegate wiring and state managementFVPTextureBasedVideoPlayerandFVPVideoPlayerfor PiP layer integrationInfo.plistbackground modes, Xcode project settings)7. Fix Android ANR on Dispose & PiP Lifecycle (
df51f0f8a)Critical stability fix:
MediaSessionsynchronously beforeExoPlayerdisposal to prevent queued media-button commands from posting to a deadHandlerthread8. Fix Missing Import (
16873e64b)Adds the missing
PipCallbackHelperimport inVideoPlayerPlugin.javathat was accidentally omitted from the PiP events commit.9. Caching, ABR Quality Control & iOS Quality Events (
dab73a0d0)Video Caching:
VideoCacheManager(Android) — manages aSimpleCachewith configurable max size for HLS/DASH segment caching via ExoPlayer'sCacheDataSourceAdaptive Bitrate (ABR) Quality Control:
getAvailableQualities()— returns list of available video renditions (bitrate, width, height, codecs)getCurrentQuality()— returns the currently selected/playing qualitysetMaxBitrate(int)— caps the adaptive selector to a maximum bitratesetMaxResolution(int width, int height)— caps the adaptive selector to a maximum resolutioniOS Quality Change Events:
FVPEventBridgeobservesAVPlayerItemaccess log notifications and emitsqualityChangedevents with bitrate/resolution infoExample App:
10. Network Error Recovery & ABR Muxed HLS Fix (
c677f2007)Configurable Network Error Recovery (Android):
AndroidVideoPlayerOptionswithmaxLoadRetries(segment-level retries) andmaxPlayerRecoveryAttempts(player-level recovery after fatal errors)ExoPlayerEventListenertracks recovery attempts, resets counter onREADYstate, surfaces error only after limit exceededDefaultLoadErrorHandlingPolicyconfigured onMediaSourceFactoryfor retry behaviorERROR_CODE_IO_BAD_HTTP_STATUSfrom transient error list (4xx/5xx are not transient)ABR Quality Fix for Muxed HLS:
TRACK_TYPE_DEFAULT(muxed HLS format) in addition toTRACK_TYPE_VIDEOinonDownstreamFormatChanged, checking for video dimensions to correctly report quality changes on muxed streams11. 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.decoderChangedeventgetAvailableDecoders(),getCurrentDecoderName(),setVideoDecoder()methodsAndroid Native:
MediaCodecSelectorto force a specific decoderMediaCodecListenumeration with cached MIME type for decoder list availability across rebuildsExample App:
DecoderRetrierbest-practice class demonstrating active error monitoring during a settle period to catch runtimeMediaCodeccrashes (not just init failures)Test Plan
maxLoadRetriesandmaxPlayerRecoveryAttemptsDecoderRetrieron a device with known bad HW decoder🤖 Generated with Claude Code