Fix ios media element start bug - #3281
Open
ne0rrmatrix wants to merge 9 commits into
Open
Conversation
Introduced IDisposable? PlayerItemStatusObserver to track AVPlayerItem status and ensure proper disposal in PlatformUpdateSource and Dispose methods. Refactored status observation to trigger MediaOpened, error handling, and video dimension updates only when ReadyToPlay. Moved video dimension, autoplay, and poster logic to OnPlayerItemReady. Improved error handling and logging for Failed status.
Removed the unnecessary 'using CommunityToolkit.Maui.Media.Services;' directive from MediaManager.macios.cs. This cleanup reduces dependencies and improves code clarity without affecting functionality.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adjusts the iOS/macOS (Mac Catalyst) MediaManager implementation so MediaElement.MediaOpened is raised only after the underlying AVPlayerItem reports ReadyToPlay, preventing “opened” state from being reported before duration/dimensions are available and before playback operations can safely succeed.
Changes:
- Adds an
AVPlayerItem.Statusobserver and routesMediaOpened/MediaFaileddecisions through that status transition instead of firing immediately after item creation. - Introduces a
hasMediaOpenedguard and disposes the new observer when switching sources and duringDispose(). - Updates speed initialization flow to defer initial behavior until item readiness.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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.
[PR] Fix iOS/macOS MediaElement.MediaOpened Fires Before AVPlayerItem is ReadyToPlay
Description of Change
This PR fixes a bug on iOS and macOS where
MediaElement.MediaOpenedfires prematurely — immediately after theAVPlayerItemobject is created, before the native AVFoundation player signals that the media is actually ready to play. This causesMediaElementto report itself as "opened" with zero duration, and subsequent playback operations (Play(),Stop(),Seek()) fail because the underlying media hasn't loaded.The Problem
In
MediaManager.PlatformUpdateSource(),MediaElement.MediaOpened()was called right afterPlayer.ReplaceCurrentItemWithPlayerItem(), gated only byPlayerItem is not null && PlayerItem.Error is null:PlayerItem.Error is nullonly confirms that theAVPlayerItemobject was created without immediate failure — it does not mean the media has loaded, has a valid duration, or is ready for playback. The correct AVFoundation readiness signal isAVPlayerItem.Status == AVPlayerItemStatus.ReadyToPlay.The Fix
The fix moves
MediaElement.MediaOpened()into a KVO observer onAVPlayerItem.Statusthat only fires when the item reachesAVPlayerItemStatus.ReadyToPlay:hasMediaOpenedfieldMediaOpenedevents across KVO callbacksPlayerItemStatusObserverpropertyAVPlayerItem.StatusPlayerItemStatusChanged()methodMediaOpened/MediaFailedat the correct timesMediaOpened()callPlatformUpdateSource()— delegates to the observerPlatformUpdateSpeed()PlayerItemStatusChanged, which callsPlayer?.Play()afterReadyToPlayPlayerItemStatusObserveris disposed when switching sources and inDispose()New
PlayerItemStatusChanged()MethodBehavior Before vs After
MediaOpenedfiresAVPlayerItemcreationAVPlayerItem.Status == ReadyToPlayDurationatMediaOpened0(media not loaded)AVPlayerItem.DurationPlay()afterMediaOpenedFailedShouldAutoPlay = falsewithSpeedsetShouldAutoPlayand doesn't play untilReadyToPlayMediaFailedwith error detailsFiles Changed
src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.macios.csLinked Issues
PR Checklist
approved(bug) — #3249 approved by @ne0rrmatrixMediaOpenedno longer fires beforeReadyToPlayDuration/Positionpopulated correctlyShouldAutoPlay = falserespectedMediaFailedinstead of silently failingmainat time of PRAdditional Information
Root Cause Detail
The AVFoundation framework uses an asynchronous loading model. Creating an
AVPlayerItemwithnew AVPlayerItem(asset)starts loading the media asynchronously. The item'sStatusproperty transitions through:Calling
MediaOpened()immediately after creation meant it fired during theUnknownstate, before the media was loaded. This manifested as:Durationreporting as0orCMTime.IndefinitePlay()failing silently or transitioning toFailedMediaOpenedevents firing before any element was actually readyManual Verification Steps
CommunityToolkit.Maui.MediaElementShouldAutoPlay = falseon one or moreMediaElementinstancesSourceto a local video resourceMediaOpenedand verify:Duration > TimeSpan.ZeroMediaWidth > 0andMediaHeight > 0Play()successfully starts playbackShouldAutoPlay = falsewith noSpeedset does not start playbackPlatforms Tested