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

Support standard actions at item playback end #745

Closed
5 tasks done
defagos opened this issue Jan 19, 2024 · 3 comments · Fixed by #780
Closed
5 tasks done

Support standard actions at item playback end #745

defagos opened this issue Jan 19, 2024 · 3 comments · Fixed by #780
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@defagos
Copy link
Member

defagos commented Jan 19, 2024

As a developer integrating Pillarbox I might want to have playback pause when playback of an item ends, so that the user can seek back into the content rather than restart playback at its beginning.

For more information see the following comment.

Acceptance criteria

  • Action at item end can be customized.
  • The demo has been updated with a setting that makes it possible to test this behavior.

Tasks

  • Provide actionAtItemEnd as mutable Player property.
  • Improve the story demo.
  • Ensure that the playback state is consistent in all cases. Most notably, after an item reaches the .ended state with rate 0, seeking elsewhere must reset the state to .paused.
  • Make sure analytics are correct (also in the special case outlined above). In particular:
    • Reach an item end with .pause behavior. An eof (resp. stop) should be received since the content was played entirely.
    • Seek elsewhere. A play should be received for a new playback session (new comScore identifier).
  • Fix behavior so that it is possible to implement automatic transitions in playlists when the behavior is .pause, see this comment.
@defagos defagos converted this from a draft issue Jan 19, 2024
@defagos defagos moved this from ✏️ Draft to 📋 Backlog in Pillarbox Jan 19, 2024
@defagos defagos removed the status in Pillarbox Jan 19, 2024
@defagos defagos added the enhancement New feature or request label Jan 19, 2024
@defagos defagos moved this to 📋 Backlog in Pillarbox Jan 19, 2024
@defagos defagos added this to the 1.0.0 milestone Jan 22, 2024
@defagos defagos moved this from 📋 Backlog to 🚧 In Progress in Pillarbox Feb 26, 2024
@defagos defagos assigned defagos and unassigned defagos Feb 26, 2024
@waliid
Copy link
Member

waliid commented Feb 28, 2024

Here is an approach on how we can proceed in a playlist to move from an item to another, and pausing the last item to keep the last frame:

struct PlayerView: View {
    @StateObject private var player = Player(items: [
        .simple(url: URL(string: "https://rts-vod-amd.akamaized.net/ww/13444390/f1b478f7-2ae9-3166-94b9-c5d5fe9610df/master.m3u8")!),
        .simple(url: URL(string: "https://rts-vod-amd.akamaized.net/ww/13444333/feb1d08d-e62c-31ff-bac9-64c0a7081612/master.m3u8")!)
    ])

    var body: some View {
        SystemVideoView(player: player)
            .ignoresSafeArea()
            .onAppear(perform: player.play)
            .onReceive(player.$currentIndex) { newValue in
                if newValue == player.items.count - 1 {
                    player.actionAtItemEnd = .pause
                }
                else {
                    player.actionAtItemEnd = .advance
                }
            }
    }
}

@defagos
Copy link
Member Author

defagos commented Feb 28, 2024

The approach of changing the actionItemEnd based on the current index described above is the right one.

The alternative naive approach described in another issue comment, something like:

.onReceive(player.propertiesPublisher.slice(at: \.playbackState).receiveOnMainThread()) { state in
    guard state == .ended else { return }
    player.advanceToNextItem()
}

for player.actionAtItemEnd = .none does not work. The onReceive modifier namely makes another subscription again when the view body is refreshed, which will lead to the current playbackState being delivered again on connect. Even if slice(at:) removes duplicates, it namely only does for the related subscription, not between subscriptions. This means the last event will be received by the onReceive closure twice when a new subscription is made.

With the above naive implementation, at item transitions, there is a body refresh (due to the published currentItem property being updated). This triggers a new subscription and leads to the onReceive closure being called twice in sequence with the .ended state, leading to the player moving two items forward instead of one (since advanceToNextItem() is called twice).

A more correct way of implementing the above would therefore be:

.onReceive(player: model.player, assign: \.playbackState, to: $playbackState)
.onChange(of: playbackState) { state in
    guard state == .ended else { return }
    model.player.advanceToNextItem()
}

with a local @State to store playbackState. This way we only get true transitions between states in the onChange closure. advanceToNextItem() is called only once.

This improved implementation is not optimal, though, as it does not provide for gapless transitions between items, unlike the implementation described in the previous comment.

Note

The implementation in the previous comment has only a view. If it had an underlying view model the corresponding code would probably be better there.

@defagos
Copy link
Member Author

defagos commented Feb 29, 2024

We had to update item status management to make it possible to handle new possible scenarios after item playback ends. If actionAtItemEnd is set to anything but .advance, the player stays at the end of the current item in the .ended state. This means that it is still possible to seek backwards.

To handle this new use case:

  • The item status is returned to .readyToPlay. Seek detection is currently implemented by checking if the timebase changes, which should only appear after playback end if the item is seeked to another position.
  • For analytics we had to improve our Commanders Act tracker implementation so that transitions to play are still possible after eof.

@defagos defagos linked a pull request Feb 29, 2024 that will close this issue
4 tasks
@github-project-automation github-project-automation bot moved this from 🚧 In Progress to ✅ Done in Pillarbox Feb 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Archived in project
2 participants