Skip to content

Commit

Permalink
[video_player_avfoundation] send video load failure even when eventsi…
Browse files Browse the repository at this point in the history
…nk was initialized late (#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).
  • Loading branch information
misos1 authored Nov 20, 2024
1 parent 1cd499e commit 2703b67
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 8 deletions.
5 changes: 5 additions & 0 deletions packages/video_player/video_player_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.6.3

* Fixes VideoPlayerController.initialize() future never resolving with invalid video file.
* Adds more details to the error message returned by VideoPlayerController.initialize().

## 2.6.2

* Updates Pigeon for non-nullable collection type support.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,39 @@ - (void)testPublishesInRegistration {
XCTAssertTrue([publishedValue isKindOfClass:[FVPVideoPlayerPlugin class]]);
}

- (void)testFailedToLoadVideoEventShouldBeAlwaysSent {
NSObject<FlutterPluginRegistrar> *registrar =
[GetPluginRegistry() registrarForPlugin:@"testFailedToLoadVideoEventShouldBeAlwaysSent"];
FVPVideoPlayerPlugin *videoPlayerPlugin =
[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar];
FlutterError *error;

[videoPlayerPlugin initialize:&error];

FVPCreationOptions *create = [FVPCreationOptions makeWithAsset:nil
uri:@""
packageName:nil
formatHint:nil
httpHeaders:@{}];
NSNumber *textureId = [videoPlayerPlugin createWithOptions:create error:&error];
FVPVideoPlayer *player = videoPlayerPlugin.playersByTextureId[textureId];
XCTAssertNotNil(player);

[self keyValueObservingExpectationForObject:(id)player.player.currentItem
keyPath:@"status"
expectedValue:@(AVPlayerItemStatusFailed)];
[self waitForExpectationsWithTimeout:10.0 handler:nil];

XCTestExpectation *failedExpectation = [self expectationWithDescription:@"failed"];
[player onListenWithArguments:nil
eventSink:^(FlutterError *event) {
if ([event isKindOfClass:FlutterError.class]) {
[failedExpectation fulfill];
}
}];
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}

#if TARGET_OS_IOS
- (void)validateTransformFixForOrientation:(UIImageOrientation)orientation {
AVAssetTrack *track = [[FakeAVAssetTrack alloc] initWithOrientation:orientation];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,13 +345,7 @@ - (void)observeValueForKeyPath:(NSString *)path
AVPlayerItem *item = (AVPlayerItem *)object;
switch (item.status) {
case AVPlayerItemStatusFailed:
if (_eventSink != nil) {
_eventSink([FlutterError
errorWithCode:@"VideoError"
message:[@"Failed to load video: "
stringByAppendingString:[item.error localizedDescription]]
details:nil]);
}
[self sendFailedToLoadVideoEvent];
break;
case AVPlayerItemStatusUnknown:
break;
Expand Down Expand Up @@ -406,6 +400,32 @@ - (void)updatePlayingState {
_displayLink.running = _isPlaying || self.waitingForFrame;
}

- (void)sendFailedToLoadVideoEvent {
if (_eventSink == nil) {
return;
}
// Prefer more detailed error information from tracks loading.
NSError *error;
if ([self.player.currentItem.asset statusOfValueForKey:@"tracks"
error:&error] != AVKeyValueStatusFailed) {
error = self.player.currentItem.error;
}
__block NSMutableOrderedSet<NSString *> *details =
[NSMutableOrderedSet orderedSetWithObject:@"Failed to load video"];
void (^add)(NSString *) = ^(NSString *detail) {
if (detail != nil) {
[details addObject:detail];
}
};
NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey];
add(error.localizedDescription);
add(error.localizedFailureReason);
add(underlyingError.localizedDescription);
add(underlyingError.localizedFailureReason);
NSString *message = [details.array componentsJoinedByString:@": "];
_eventSink([FlutterError errorWithCode:@"VideoError" message:message details:nil]);
}

- (void)setupEventSinkIfReadyToPlay {
if (_eventSink && !_isInitialized) {
AVPlayerItem *currentItem = self.player.currentItem;
Expand Down Expand Up @@ -587,6 +607,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'
// https://github.com/flutter/flutter/issues/151475
// https://github.com/flutter/flutter/issues/147707
if (self.player.currentItem.status == AVPlayerItemStatusFailed) {
[self sendFailedToLoadVideoEvent];
return nil;
}
[self setupEventSinkIfReadyToPlay];
return nil;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_avfoundation
description: iOS and macOS implementation of the video_player plugin.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.6.2
version: 2.6.3

environment:
sdk: ^3.3.0
Expand Down

0 comments on commit 2703b67

Please sign in to comment.