-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[video_player_avfoundation] send video load failure even when eventsink was initialized late #7194
Conversation
3ea2335
to
756f3b9
Compare
756f3b9
to
16d3d7a
Compare
@@ -406,9 +400,46 @@ - (void)updatePlayingState { | |||
_displayLink.running = _isPlaying || self.waitingForFrame; | |||
} | |||
|
|||
- (void)sendFailedToLoadVideoEvent:(NSError *)error { | |||
if (!NSThread.isMainThread) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks like sendFailedToLoadVideoEvent
is only called from background queue. Can this function simply be:
- (void)sendFailedToLoadVideoEventOnMainQueue:(NSError *)error {
dispatch_async(dispatch_get_main_queue(), ^{
// all logic here
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is also called from setupEventSinkIfReadyToPlay
and observeValueForKeyPath
. I can make it without any "dispatch" and use dispatch_async
just in trackCompletionHandler
(or maybe performSelector
like is already used in this function here performSelector:_cmd
).
I have a hard time understanding this in the PR description:
Could you rephrase a bit? That'd be helpful for a review. Thanks! |
stringByAppendingString:[item.error localizedDescription]] | ||
details:nil]); | ||
} | ||
[self sendFailedToLoadVideoEvent:item.error]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: sendFailedToLoadVideoEventIfNeeded
since you moved the check inside
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not say "if needed" sounds right here. Meaning of that check is rather like "if can" or "if possible".
}; | ||
NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey]; | ||
// add more details to error message | ||
// https://github.com/flutter/flutter/issues/56665 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont think we need this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can remove this link.
// if status is Failed here then this was called from onListenWithArguments which means | ||
// _eventSink was nil when was called observeValueForKeyPath with updated Failed status | ||
// and error was not sent and never will be so it is needed to send it here to have | ||
// future returned by initialize resolved instead of in state of infinite waiting, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you separate these 4 lines into multiple sentences? I have a hard time understanding this.
return; | ||
case AVKeyValueStatusFailed: | ||
// if something failed then future should result in error | ||
[self sendFailedToLoadVideoEvent:error]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also specify which thread this is on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On some AVFoundation background queue (this is also mentioned in a comment a few lines above):
// https://github.com/flutter/flutter/issues/151475 | ||
// https://github.com/flutter/flutter/issues/147707 | ||
if (currentItem.status == AVPlayerItemStatusFailed) { | ||
[self sendFailedToLoadVideoEvent:currentItem.error]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we move this to the caller, before setupEventSinkIfReadyToPlay
is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or can you update the function name to setupEventSinkIfReadyToPlayOrReportFailure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is also 4th place where this function is called masked by _cmd
here self performSelector:_cmd
, I would rather not put that check outside of that function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually that function does not set up _eventsink
, I would say it is set up by onListenWithArguments
. This function just sends an event through that event sink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand if status becomes failed
on that second call it should be already caught in the key observer where the event sink is not nil and so it would send an error from there.
case AVKeyValueStatusFailed: { | ||
// if something failed then future should result in error | ||
dispatch_async(dispatch_get_main_queue(), ^{ | ||
[self sendFailedToLoadVideoEvent:error]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this code the key change that fixed the bug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems no, I think it is that change in onListenWithArguments
. But without that change it seems also this change works as I now tested it with "Code sample 1" from flutter/flutter#151475.
@@ -587,6 +613,13 @@ - (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments | |||
// This line ensures the 'initialized' event is sent when the event | |||
// 'AVPlayerItemStatusReadyToPlay' fires before _eventSink is set (this function | |||
// onListenWithArguments is called) | |||
// and also send error in similar case with 'AVPlayerItemStatusFailed' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by "similar case", do you mean AVPlayerItemStatusReadyToPlay fires before _eventSink is set? Can you be more explicit here in the comment? (Sorry I have some trouble understanding this bug fix)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I was following up with that comment above. But this time with AVPlayerItemStatusFailed
instead of AVPlayerItemStatusReadyToPlay
. If anything fires before is event sink set then it could not be sent. Would that comment be better if I added "in similar case as above"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay.
// and also send error in similar case with 'AVPlayerItemStatusFailed' | ||
// https://github.com/flutter/flutter/issues/151475 | ||
// https://github.com/flutter/flutter/issues/147707 | ||
if (self.player.currentItem.status == AVPlayerItemStatusFailed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is the part that actually fix the bug? Can you add a comment explaining how we ended up with Failed state here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I did not manage to proceed with this. Yes when AVPlayerItemStatusFailed
fires before _eventSink
is set. AVPlayerItem
is "started" to do its things and can asynchronously become ReadyToPlay
or Failed
before the dart side starts to listen where onListenWithArguments
is called. My comment here follows up that comment before which tries to explain this but that previous fix connected with that comment omitted Failed
state as possible state here which this line fixes (if player item can end up with success here it can also end up with failure, so that previous comment should explain it).
@hellohuanlin Please add tarrinneal (the ecosystem-level CODEOWNER) as the secondary reviewer once this has passed iOS review; the iOS team review is primary since this is internal to the iOS implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM after the nit on comment
…en eventsink was initialized late (flutter/packages#7194)
flutter/packages@e95f6d8...913b99e 2024-11-21 brackenavaron@gmail.com [vector_graphics] handle errors from bytes loader (flutter/packages#8080) 2024-11-21 8276375+derdilla@users.noreply.github.com [flutter_svg] Fix SvgNetworkLoader not closing internal http client (flutter/packages#8126) 2024-11-20 30872003+misos1@users.noreply.github.com [video_player_avfoundation] send video load failure even when eventsink was initialized late (flutter/packages#7194) 2024-11-20 kevmoo@users.noreply.github.com [flutter_markdown] enable Wasm support (flutter/packages#8120) 2024-11-20 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[url_launcher] Add Swift Package Manager integration to example app (#8128)" (flutter/packages#8136) 2024-11-20 737941+loic-sharma@users.noreply.github.com [url_launcher] Add Swift Package Manager integration to example app (flutter/packages#8128) 2024-11-20 stuartmorgan@google.com [pigeon] Enable example app build in CI (flutter/packages#8119) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
* main: (64 commits) [quick_actions_plaform_interface] add localizedSubtitle (flutter#8112) [tools] Don't check license of generated Swift package (flutter#8137) Roll Flutter from 8536b96ebb3e to 93d772c5cdd8 (37 revisions) (flutter#8147) [go_router] Fix: Consistent PopScope Handling on Root Routes issue #140869 (flutter#8045) [in_app_purchase_storekit] fix price displayed with wrong precision (flutter#8127) [pigeon] Removes the `@protected` annotation from the InstanceManager field of the `PigeonInternalProxyApiBaseClass` (flutter#8125) [google_maps_flutter] Use structured Pigeon data on iOS (flutter#8142) [vector_graphics] handle errors from bytes loader (flutter#8080) [flutter_svg] Fix SvgNetworkLoader not closing internal http client (flutter#8126) [video_player_avfoundation] send video load failure even when eventsink was initialized late (flutter#7194) [flutter_markdown] enable Wasm support (flutter#8120) Reverts "[url_launcher] Add Swift Package Manager integration to example app (flutter#8128)" (flutter#8136) [url_launcher] Add Swift Package Manager integration to example app (flutter#8128) [pigeon] Enable example app build in CI (flutter#8119) [in_app_purchase_storekit] disallow ios versions lower than supported from enabling storekit (flutter#8110) [interactive_media_ads]: Bump com.google.ads.interactivemedia.v3:interactivemedia from 3.35.1 to 3.36.0 in /packages/interactive_media_ads/android (flutter#8046) [interactive_media_ads]: Bump androidx.annotation:annotation from 1.8.2 to 1.9.1 in /packages/interactive_media_ads/android (flutter#7980) [webview_flutter_android] Updates plugin to use `ProxyApis`s (flutter#7794) [interactive_media_ads] Adds support to define parameters that control the rendering of ads (flutter#8057) Roll Flutter from b3818f6b5979 to 8536b96ebb3e (22 revisions) (flutter#8124) ... # Conflicts: # packages/quick_actions/quick_actions_platform_interface/CHANGELOG.md
I forgot to prepend those 3 issues with |
Thanks, I closed one, and left a comment in another that is likely fixed but needs re-testing (unless you've already tested that one? If so we can close it). For the third it's not clear to me whether it's fully resolved. |
That first which you closed actually contained another behaviour which is not covered by this PR. But I think it is rather not a fault in the package or flutter sdk but rather with something how flutter runs apps on ios devices. Seems sometimes the app "disappears" after running but after closer inspection it seems it was just probably somehow "pushed" to background. I probably tested the second with some text file but I am not sure and probably not with that original file and probably not on macos either. Anyway the best would be confirmation from the author. That third is a mess. Seems there are several different groups who interpret that issue differently. Sticking to what author wrote in description and repeated in comments seems that the issue is just about better error message flutter/flutter#56665 (comment). So the question is whether issue should be interpreted differently if a lot of users expect that that issue should be closed by fixing underlying behaviour (which probably cannot be done from flutter or video_player side as it does not have anything to do with http communication here, if of course there is not some flag somewhere in AVFoundation). Maybe better to ask the author also here (or maybe wait and see if any new comments are added in next few months). |
…nk was initialized late (flutter#7194) Event `initialized` is sent from `onListenWithArguments` by calling `setupEventSinkIfReadyToPlay` if event sink was `nil` during `observeValueForKeyPath`. This change also sends failure in a similar way. Adds more details to the error message returned by `VideoPlayerController.initialize()`. - flutter/flutter#151475 - flutter/flutter#147707 - flutter/flutter#56665 - now error message may look like: `Failed to load video: Operation Stopped: The server is not correctly configured.: The operation couldnâ��t be completed. (CoreMediaErrorDomain error -12939 - byte range and no content length - error code is 200)` Tests `testSeekToWhilePausedStartsDisplayLinkTemporarily` and `testSeekToWhilePlayingDoesNotStopDisplayLink` are failing on the main branch on ios. Seems position is correctly set to 1234 in `seekTo` completion handler but right after `[mockDisplayLink setRunning:YES]` is set again to 0 and after some time back to 1234 so those two tests sometimes fail (seems more often when running all tests).
Event
initialized
is sent fromonListenWithArguments
by callingsetupEventSinkIfReadyToPlay
if event sink wasnil
duringobserveValueForKeyPath
. This change also sends failure in a similar way. Adds more details to the error message returned byVideoPlayerController.initialize()
.Failed to load video: Operation Stopped: The server is not correctly configured.: The operation couldn’t be completed. (CoreMediaErrorDomain error -12939 - byte range and no content length - error code is 200)
Tests
testSeekToWhilePausedStartsDisplayLinkTemporarily
andtestSeekToWhilePlayingDoesNotStopDisplayLink
are failing on the main branch on ios. Seems position is correctly set to 1234 inseekTo
completion handler but right after[mockDisplayLink setRunning:YES]
is set again to 0 and after some time back to 1234 so those two tests sometimes fail (seems more often when running all tests).Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style, or this PR is exempt from CHANGELOG changes.///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.