Skip to content
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

Crash during continuous playback transitions #259

Closed
defagos opened this issue Feb 22, 2022 · 8 comments
Closed

Crash during continuous playback transitions #259

defagos opened this issue Feb 22, 2022 · 8 comments
Milestone

Comments

@defagos
Copy link
Member

defagos commented Feb 22, 2022

The app crashes when a new media is being played after continuous playback display.

Issue type

Crash

Description of the problem

Stack trace:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1c)
    frame #0: 0x00000001800a35bc libobjc.A.dylib`object_isClass + 16
    frame #1: 0x0000000181253f4c Foundation`KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED + 44
    frame #2: 0x0000000181253d60 Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 268
    frame #3: 0x000000018125461c Foundation`-[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68
    frame #4: 0x000000018124d1d4 Foundation`_NSSetObjectValueAndNotify + 284
    frame #5: 0x0000000194248a44 AVKit`-[AVInterstitialController dealloc] + 32
    frame #6: 0x00000001800c0954 libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) + 204
    frame #7: 0x00000001800c0824 libobjc.A.dylib`objc_autoreleasePoolPop + 236
    frame #8: 0x0000000180745e10 CoreFoundation`_CFAutoreleasePoolPop + 28
    frame #9: 0x00000001806a470c CoreFoundation`__CFRunLoopPerCalloutARPEnd + 44
    frame #10: 0x000000018069f9c4 CoreFoundation`__CFRunLoopRun + 2516
    frame #11: 0x000000018069eae4 CoreFoundation`CFRunLoopRunSpecific + 572
    frame #12: 0x00000001835bd5ec GraphicsServices`GSEventRunModal + 160
    frame #13: 0x00000001adc2eac4 UIKitCore`-[UIApplication _run] + 992
    frame #14: 0x00000001adc335e0 UIKitCore`UIApplicationMain + 112
  * frame #15: 0x0000000100fdb6c8 SRGLetterbox-demo`main(argc=1, argv=0x000000016ee2daf0) at main.m:14:16
    frame #16: 0x0000000101671ca0 dyld_sim`start_sim + 20
    frame #17: 0x00000001017710f4 dyld`start + 520

This is an issue with interstitials and KVO, probably a regression of tvOS 15.

Environment information

  • Library version: Tested with 7.3.2
  • tvOS version: Reproduced with 15.3 and 15.4 beta. No crash with 14.7.
  • Device: Any

Reproducibility

Always reproducible

Steps to reproduce

  1. Enabled continuous playback in Letterbox demo.
  2. Play a video and seek near the end.
  3. Wait until the continuous playback overlay is displayed and play the next media. The crash occurs as the new media is being loaded.
@defagos
Copy link
Member Author

defagos commented Feb 22, 2022

This is likely a tvOS 15 regression, probably in the way tvOS deals with interstitial updates or when an AVPlayer(Item) instance gets deallocated. We must probably create a sample project and report the issue to Apple, as we do nothing special with interstitials (except updating them).

I guess we should create a small AVPlayerViewController example:

  1. Attach some AVPlayer with interstitials (or empty array).
  2. Replace with some other AVPlayer with interstitials (or empty array).

@defagos
Copy link
Member Author

defagos commented Feb 22, 2022

I can simply reproduce the issue in SRG Media Player demo by switching the media after some while in the SRG Media Player View Controller demo:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [playerViewController.controller playURL:media.URL];
});

No matter whether the player item interstitial property is set or not, the crash occurs. So a good sample project could be:

  1. Use AVPlayerViewController with an associated AVPlayer instance and KVObserve its player property and investigate what kind of code executed upon KVObservation (via MAKVONotificationCenter blocks in our case, which could add their own share of issues) could be responsible of the crash.
  2. Swap the player instance with another one.

By experimenting a bit with the code executed upon KVObservation of player changes we might be able to figure out what causes the crash.

@defagos
Copy link
Member Author

defagos commented Feb 23, 2022

The following AVPlayerViewController sample does not crash, so we might find something in our code which explains the crash by swapping the NSLog with code involving more player changes like those we do in our current SRGMediaPlayerViewController implementation:

NSURL *URL = ...;

AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.delegate = self;
AVPlayer *player = [AVPlayer playerWithURL:URL];
playerViewController.player = player;
[self presentViewController:playerViewController animated:YES completion:^{
    [player play];
}];

@weakify(playerViewController)
[playerViewController addObserver:self keyPath:@keypath(playerViewController.player) options:0 block:^(MAKVONotification *notification) {
    @strongify(playerViewController)
    NSLog(@"--> %@", playerViewController);
}];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    playerViewController.player = [AVPlayer playerWithURL:URL];
    [playerViewController.player play];
});

@defagos
Copy link
Member Author

defagos commented Feb 23, 2022

Crash is likely due to -bindToPlayerViewController: being called when player changes are detected with KVO. Seems to be related to the fact that we ultimately assign playerViewController.player = self.player from within the KVO block.

@defagos
Copy link
Member Author

defagos commented Feb 23, 2022

Code to reproduce the crash with AVPlayerViewController only. A bit contrived since we are observing changes to the player property to apply them again via KVO, but this leads to the exact same crash and could be helpful in finding a solution:

NSURL *URL = ...;

[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"System player", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
    playerViewController.delegate = self;
    AVPlayer *player = [AVPlayer playerWithURL:URL];
    playerViewController.player = player;
    [self presentViewController:playerViewController animated:YES completion:^{
        [player play];
    }];

    @weakify(playerViewController)
    [playerViewController addObserver:self keyPath:@keypath(playerViewController.player) options:0 block:^(MAKVONotification *notification) {
        @strongify(playerViewController)
        playerViewController.player = player;
    }];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        playerViewController.player = [AVPlayer playerWithURL:];
        [playerViewController.player play];
    });
}]];

@defagos
Copy link
Member Author

defagos commented Feb 23, 2022

It might be related to the deallocation of the previous player instance, rather than to the assignment to the player view controller. This should be further investigated.

@defagos
Copy link
Member Author

defagos commented Feb 24, 2022

The crash randomly occurs when setting the AVPlayerViewController player property to nil. This is done in our current implementation when switching between medias since the player is reset first to nil.

This can be reproduced in a sample project which I will submit to Apple. I also suspect we can find a workaround in the meantime.

If we try to set the property to an AVPlayer instance (e.g. one instantiated with -new) the crash still occurs. It is likely that the issue is not related to the value itself, but to the fact we are setting several times the player view controller player property in a row. Maybe a viable workaround would perform additional checks to avoid performing several changes in a row if not necessary.

It is also very likely that this issue would be less of a problem if we were using a single AVQueuePlayer instance per controller, see #252.

@pyby
Copy link
Member

pyby commented Feb 28, 2022

@defagos Nice bug understanding.

Enabling auto play in Letterbox demo and displaying the continuous playback screen, no more crashes on tvOS.

@pyby pyby closed this as completed Feb 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants