SRGSSR / srgmediaplayer-apple

An advanced media player library, simple and reliable
MIT License
159 stars 33 forks source link

Device lock prevented while playing a video in background #84

Closed defagos closed 4 years ago

defagos commented 4 years ago

Starting with iOS 12, video playback (even in background) prevents the device from locking by default. This should be avoided.

See https://github.com/SRGSSR/playsrg-ios/issues/139.

defagos commented 4 years ago

This is due to changes to background playback behavior introduced with iOS 12.

Below iOS 12

As tested with devices running iOS 9, 10 and 12:

iOS 12 and above

With iOS 12, Apple introduced changes to background playback, some of them previously lead to issues on our side (see #66). By default, the behavior is now:

To compensate for this new video background behavior, a new preventsDisplaySleepDuringVideoPlayback property has been added. This new abilities were probably introduced for experiences where video playback is not a highly interactive experience (e.g. autoplay in a news timeline, animated background for a login screen, etc.).

Our SRG Media Player controller should better manage this property so that video playback (either without attached layer or in background) never prevents the device from locking, as for audio.

We should have SRG Media Player automatically manage it so that, in cases where this does not

defagos commented 4 years ago

We must be especially careful to have a good behavior for the following use cases:

We must therefore use the value provided by the user in the player configuration block, and possibly override it in the above use cases so that the behavior is the best possible one.

defagos commented 4 years ago

A fix proposal has been made on the feature/screen-lock-fix branch. I tested it quite extensively but, since there is no way to unit test this behavior, further manual tests will probably be helpful.

defagos commented 4 years ago

I tested this fix in our Play app and... well, it does not work there. Device lock is not prevented, but playback sometimes pauses when going to background, even if the video layer has been detached.

I have an idea why this might happen, I'll investigate a fix for the fix.

defagos commented 4 years ago

Testing is a bit cumbersome and can only be manual. The device must also be detached from any debugger, which otherwise prevents the device from sleeping. It is best to kill and restart the app, this behavior could even persist when detaching the cable during my tests.

The main idea can be summarised as follows: If a view is attached to the player and installed in the view hierarchy, and if preventsDisplaySleepDuringVideoPlayback is set to YES, the device is prevented from sleeping while the media is playing. In all other cases the device can enter sleep mode.

I updated the inline demo so that playing with all kinds of different setups is easy. Just build the demo, end the debugging session and check that the following expected behaviours are fulfilled when playing a video. You should set device sleep duration to a minimum (30 seconds on an iPhone, 2 minutes on iPad):

Video playback on iOS 12+

View attached to the player Video prevents sleep Device prevented from sleeping?
Yes Yes Yes, but only when the video is playing
Yes No No
No Yes No
No No No

Video playback for iOS 11 and below

The device is always prevented from sleeping when video is playing, whether the player is bound to an installed view or not.

defagos commented 4 years ago

Fixed on the feature/background-behavior-fixes branch. The results above have been verified in SRG Media Player, as well as in all of our SRG Media Player based products, following the same approach.

defagos commented 4 years ago

We still had an issue in our Play app nightlies. In some cases (yet to be determined), the screen could sleep even with a playing video visible.

defagos commented 4 years ago

I have an example of a use case where the behavior is incorrect in Play SRG

  1. Enable background video playback
  2. Play video
  3. Reduce to mini player
  4. Wait until the device sleeps
  5. Unlock the device
  6. Reopen the full screen player with the still playing video
  7. Wait. Device incorrectly sleeps

This would naively translate to the following use case for SRG Media Player inline demo:

  1. Open the inline demo with a video content selected.
  2. Enable Detached mode
  3. Prepare to play and start playing the video
  4. Detach the player view, wait until the device sleeps
  5. Unlock the device
  6. Reattach the player view with the still playing video
  7. Wait

In Media Player demo, though, this seems to work.

defagos commented 4 years ago

Also experienced with the following use case:

  1. Enable background video playback
  2. Play video
  3. Send app to the background
  4. Wait until the device sleeps
  5. Unlock the device
  6. Reopen the app, still playing the video
  7. Wait. Device incorrectly sleeps
defagos commented 4 years ago

Also experienced with the following use case:

  1. Enable background video playback
  2. Play video
  3. Lock the device
  4. Wait more than the device sleep delay
  5. Unlock the device
  6. The app still plays the video
  7. Wait. Device incorrectly sleeps

With the exact same procedure, but without waiting more than the device delay, this works correclty!

We don’t do anything different whether the device is locked by the user or whether the sleep delay is reached. Is there some undocumented behavior we don’t know of?

defagos commented 4 years ago

I confirm this is related to the fact that the device entered sleep mode on its own once. The following does not work either:

  1. Enable background video playback
  2. Play video
  3. Pause playback.
  4. Wait until the device sleeps.
  5. Unlock the device
  6. Resume video playback
  7. Wait. Device incorrectly sleeps

With the exact same procedure, but without waiting more than the device delay, this works correclty!

We don’t do anything different whether the device is locked by the user or whether the sleep delay is reached. Is there some undocumented behavior we don’t know of?

defagos commented 4 years ago

There is also a slight audio interruption when attaching or detaching the layer in the inline demo. This problem didn't exist before.

defagos commented 4 years ago

In understood what is going wrong: The -reloadPlayerConfiguration persists the current value forever if it occurs while the values is overridden. Once set to NO, it keeps this value forever (unless of course the configuration is reset).

The reason this appears in Letterbox is because Letterbox calls -reloadPlayerConfiguration, whereas the inline SRG Media Player demo doesn't.

The current SRG Media Player implementation is therefore incorrect and must be fixed. I might already have a proposal but I need to test it thoroughly first.

pyby commented 4 years ago

Thank you for resuming all those test cases. To not forget, I repeat that I found too:

Video playback for iOS 11 and below

The device is always prevented from sleeping when video is playing, whether the player is bound to an installed view or not.


One case still have an issue: SRGMediaPlayViewController + Picture in Picture on iOS 12+.

  1. Play video with SRG Media Player player on an iPad.
  2. Send app to the background (Picture in Picture starts).
  3. Wait. Device incorrectly sleeps.

From reloadPlayerConfiguration:

Also:

The correct behaviour founded with System and Advanced Custom players.

defagos commented 4 years ago

To fix the SRGMediaPlayerViewController issue, I propose we simply disable overrides in this case. We do not control the picture in picture controller in this case, so we cannot rely on it.

Applications which want a custom behavior in this case (highly unlikely) can still implement the mechanism they need with playerConfigurationBlock and AVPlayerViewControllerDelegate.