SRGSSR / pillarbox-apple

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

Picture in Picture PoC #605

Closed defagos closed 11 months ago

defagos commented 11 months ago

As a Pillarbox developer I want to have a better understanding of how picture in picture could be implemented in Pillarbox so that any SwiftUI- or UIKit-based application is able to easily implement this feature.

Acceptance criteria

Hints

Expected behaviors to implement / work correctly

Tasks

defagos commented 11 months ago

Possible integration scenarios for PiP to consider for the final implementation:

defagos commented 11 months ago

A first PoC has been pushed onto the archive/605/picture-in-picture-poc-1 branch. Here are a few learnings extracted from this PoC which could be useful for our future implementation.

Player layer management

SRG Media Player implemented lazy view instantiation (and storage) at the controller level. This now appears to be fundamentally flawed:

The PoC implementation shows that a much simpler way of managing PiP is possible:

What is still not clear at the end of this PoC is where the PiP controller should be stored. The PoC stores the PiP controller at a singleton level (since there is only one active PiP session at most) but this means that we cannot have different PiP states associated with separate VideoViews. There is only one truth.

We could imagine having several PiP-enabled views on screen, though, each being able to start PiP independently. When entering PiP the controller (and thus the layer) would be shared to a central service (similar to the PictureInPicture of the PoC) managing the single possible active PiP session and restoration from it. This last approach might not be feasible, though, since we cannot be sure which instance would win when the application is sent to the background. So this requires a bit more investigation first (if not we already have a viable strategy).

Possible implementation strategies

The video view should provide opt-in support for PiP, e.g.

Video view implementation

We need to be able to build a video view from a layer, thus our implementation needs to be slightly revisited so that the player layer is a sublayer of the video view, either freshly instantiated or created with a layer received from a PiP controller.

Possible PiP integrations

Having PiP support entirely separated from Player has another benefit. It namely allows users to implement PiP easily with reduced capabilities, or in a deeper way.

Simple client-side PiP integration

The Netflix PiP integration does not provide any PiP button. PiP can only be enabled when sending the app to the background. In this case the player view from which the layer is detached is never dismissed, there is therefore no way to persist any particular state so that PiP can continue.

In this case the only action required to support PiP is to use a view supporting it. All the rest is handled internally and there is no restoration mechanism to implement. No PiP button must be provided to the user.

The only downside of this integration is that the user cannot browse the app while playing content. They are always stuck at the player level.

In comparison to Letterbox the fact that PiP should be handled at the view level only means we can have simple PiP integrated in no time in all apps, which was previously not possible.

Deeper PiP integration

Apple tv+ PiP integration ensures that the app can be navigated while PiP is active. This requires persistence when the player view is dismissed.

Apps should have a view model for their player UI (in the simplest case this VM is the Player itself, but if more logic is required a proper VM owning a Player would be more appropriate). Restoration is simply achieved using a view able to reflect the VM and present it again.

Learnings

We learned more things along the way:

UIKit implementation

The UIKit implementation does not require more work:

A question remains, namely whether we should provide a state publisher for the PiP management service, PictureInPicture in the PoC, so that UIKit apps can easily register to changes. But maybe simple KVObservability suffices.

Challenges

SwiftUI demo

We could:

UIKit demo

We could write a simple separate UIKit demo, like in the PoC. But we should ensure it always compiles correctly, even if it is a small sample app.

Documentation

We should likely provide document both for basic PiP integration (basically free) as well as deeper integration, which requires more involved view model design work but can still be nicely integrated with reusable view components having a Player as parameter.

Open questions