SRGSSR / pillarbox-apple

A next-generation reactive media playback ecosystem for Apple platforms.
https://testflight.apple.com/join/TS6ngLqf
MIT License
54 stars 8 forks source link

Support advanced PiP integration #612

Closed defagos closed 11 months ago

defagos commented 11 months ago

As a developer integrating Pillarbox I want to be able to implement PiP deeper in my application, so that users can browse the application while continuing playback using PiP.

As a Pillarbox user I want to be able to use the app while watching content.

Acceptance criteria

Hints

Tasks

defagos commented 9 months ago

I finally could understand why sometimes we observed Picture in Picture being paused during restoration, not from the PiP overlay itself, but by starting playback of another content. This investigation and the related fix were made as part of #702.

When do pauses occur?

Pauses occur when transitioning via PiP from some content A, played with a player supporting PiP, to some content B, played in the same player but not supporting PiP.

Compare:

  1. Content A played with a player supporting PiP, transitioning via PiP to content B in the same player supporting PiP:

    https://github.com/SRGSSR/pillarbox-apple/assets/170201/eea74446-2275-45ff-8ac2-69c5361d674f

  2. Content A played with a player supporting PiP, transitioning via PiP to content B in the same player not supporting PiP:

    https://github.com/SRGSSR/pillarbox-apple/assets/170201/64de7277-f7c6-4b8c-8070-0febd4693d93

In the first case playback continues, while in the second one playback is paused.

Remark

You might think that this case is convoluted but actually it isn't. The fact that a view supports PiP not only supposes that the video view has been configured appropriately, but also that the view itself is installed in the hierarchy and therefore could register itself with a Picture in Picture controller.

Depending on how a player user interface is implemented the view might not be immediately available, e.g. if the implementation only displays the video view once the media type is known (see #696 for a related issue that needed to be fixed as well). This is perfectly legitimate and can happen in practice. We have no way of preventing such implementations and we cannot have behaviors break just because of subtle layout implementation refactorings that are part of any development process.

Why do pauses occur when transitioning to a layout not-supporting PiP?

Our implementation explicitly stops Picture in Picture using the dedicated API when a video view appears for the first time (via onAppear(perform:)). To better understand what happens let us have a look at what we have if we remove the stop and let PiP playback continue in the overlay. We then simulate the stop by tapping the restoration button in the PiP overlay:

  1. Content A played with a player supporting PiP, transitioning via PiP to content B in the same player supporting PiP:

    https://github.com/SRGSSR/pillarbox-apple/assets/170201/8c203cfe-2afc-4f84-8cb5-e75ae8bef5f6

  2. Content A played with a player supporting PiP, transitioning via PiP to content B in the same player not supporting PiP:

    https://github.com/SRGSSR/pillarbox-apple/assets/170201/8bff9237-8984-4306-8a22-402452357ab6

We can easily understand what happens now:

How can we fix this issue?

To fix the issue visible in the second scenario we need to detach the player from the PiP layer before PiP is stopped, but only when the view we are transitioning to does not support PiP anymore. This way we avoid the player being shared and pausing playback in the other layer when PiP is closed:

https://github.com/SRGSSR/pillarbox-apple/assets/170201/217ca526-5965-4312-846e-09562e91b408

The programmatic PiP stop is not even needed in this case since this change forces PiP to close automatically. The stop is still needed for the first scenario, though, so that the PiP overlay is properly returned when transitioning to the same view supporting PiP.

defagos commented 9 months ago

Here are a few use cases as a reminder of expected behaviors that should possible to implement and test in the demo. This is of course no perfect replacement for proper unit testing but at least better than having nothing.

In all cases:

Note that the behaviors listed above are mostly a matter of proper route management. Our API, though, must have the flexibility so that these behaviors can be implemented.

Restoration with PiP overlay restoration button

https://github.com/SRGSSR/pillarbox-apple/assets/170201/2252466f-9fe4-4151-b73a-1a29ce97836b

Remark

PiP must be possible simultaneously with other views backed by separate models. Restoration must also be possible.

https://github.com/SRGSSR/pillarbox-apple/assets/170201/1d4dfe27-159c-49ed-a000-9223290c2384

Restoration by opening the same content with the same model

https://github.com/SRGSSR/pillarbox-apple/assets/170201/a2b96848-a06d-4712-ad21-26f3b9e5ea93

Restoration by opening another content with the same model

https://github.com/SRGSSR/pillarbox-apple/assets/170201/4fd77658-67b0-4ea2-976c-bc2621ba4b40

Remark

If going through several contents played with the same model / player, the latest content must be restored (in the video below Couleur 3 is restored, not the first opened SWI content):

https://github.com/SRGSSR/pillarbox-apple/assets/170201/d37ab7e5-71a6-4c71-9756-2887e4eb3abb

Restoration by opening another 360° content with the same model

Monoscopic display does not support PiP.

https://github.com/SRGSSR/pillarbox-apple/assets/170201/394341cc-f5ff-468f-aa6b-69c68408004b

Restoration by opening another failing content with the same model

https://github.com/SRGSSR/pillarbox-apple/assets/170201/758f59b3-0f50-4019-9b3a-a5cbe49e3bdf

Restoration to another view model with PiP-supporting VideoView

In this case PiP must be stopped since there can be at most a single VideoView enabled for PiP, no matter to which model it is connected.

https://github.com/SRGSSR/pillarbox-apple/assets/170201/6e84c9c0-779d-42ac-8550-1ed21a89902f

Restoration with multiple views involved

https://github.com/SRGSSR/pillarbox-apple/assets/170201/f04082bd-d951-4238-ba14-91cbaf05f4b8

Restoration by opening the same content with the same model, starting PiP from a custom view and restoring it with a custom view which does not support PiP anymore

https://github.com/SRGSSR/pillarbox-apple/assets/170201/25469730-1817-4daf-b758-8a3a10c8ab90

Restoration by opening the same content with the same model, starting PiP from a system view and restoring it with a system view which does not support PiP anymore

https://github.com/SRGSSR/pillarbox-apple/assets/170201/f563f360-4cde-423e-8360-89a75649ae83

Restoration by opening the same content with the same model, starting PiP from a custom view and restoring it with the system view supporting PiP

https://github.com/SRGSSR/pillarbox-apple/assets/170201/7d51f55c-1757-4a6c-9f72-e61c074ea97d

Restoration by opening the same content with the same model, starting PiP from the system view and restoring it with a custom view supporting PiP

https://github.com/SRGSSR/pillarbox-apple/assets/170201/8d9c0700-38d4-445f-9b12-b45bc6090c86

Inline system player

https://github.com/SRGSSR/pillarbox-apple/assets/170201/f0817170-913e-4445-b011-d242378792f4