Documentation
¶
Overview ¶
Package autoadvance moves playlists on without anyone pressing next.
A playlist item is "bound" when the launch that played it published media in its slot: only then does the engine know that when that media ends, the item is what ended, and only then may it act. Media that appeared any other way, such as a game started from the menu, is never bound and is never touched. Every automatic move is also guarded: the playlist must still be the active one, on the same item, playing and not stopped by a failure, so a user who got there first always wins.
What happens when bound media ends depends on why it ended. Media that finished moves the playlist on at once. A game that exited by itself gets a cancellable "up next" countdown, or, if it was started automatically and quit within seconds, pauses the playlist instead, since the user plainly did not want it. Anything Core stopped or replaced never advances.
Two timers rotate a playlist while its media is still running. An advance timer runs from the moment an item's media appears and freezes while the playlist is paused. An idle timer measures time without input and only runs where the platform reports keyboard, mouse and controller activity; it starts a loaded ("armed") playlist, rotates a playing one, and carries on a playlist whose game has exited, but never rotates away from media the playlist did not launch.
All state belongs to one goroutine. Observer callbacks and the other inputs only append to an unbounded queue, so they never block the code that reports them, and no event is ever dropped. Deadlines are never trusted to a timer firing: after every event and every wakeup the loop compares each deadline with the clock, so a late or spurious wakeup does no harm.
Index ¶
- Variables
- func IdleSupported(pl platforms.Platform) bool
- type Config
- type Engine
- func (e *Engine) ItemLaunched(pls *playlists.Playlist, err error, publishesLater bool)
- func (e *Engine) ItemLaunching(pls *playlists.Playlist)
- func (e *Engine) ItemRefused(pls *playlists.Playlist)
- func (e *Engine) MediaEnded(end state.MediaEnd)
- func (e *Engine) MediaStarted(start state.MediaStart)
- func (e *Engine) NoteUserActivity()
- func (e *Engine) PlaylistChanged(slot string)
- func (e *Engine) Start(ctx context.Context)
- func (e *Engine) Stop()
- func (e *Engine) Sync()
- type Host
- type UIOpener
Constants ¶
This section is empty.
Variables ¶
var ErrIdleUnsupported = errors.New(
"idle rotation is not available: this device cannot detect keyboard, mouse and controller activity",
)
ErrIdleUnsupported is returned when idle rotation is asked for on a device that cannot see all of the input it would have to wait for.
Functions ¶
func IdleSupported ¶
IdleSupported reports whether the platform can detect keyboard, mouse and controller activity, which idle rotation needs: without all three it would switch games under someone who is still playing.
Types ¶
type Config ¶
type Config struct {
Clock clockwork.Clock
Host Host
// UI opens countdown prompts. It may be nil.
UI UIOpener
// Input reports user input. It may be nil, in which case input never
// cancels a countdown and idle rotation cannot run.
Input platforms.InputActivitySource
// PublishesLater reports whether media from the launcher with this ID is
// published by an external tracker after the launch call returns. Media
// that waits on a launch is bound only if it says so. Nil accepts any
// launcher.
PublishesLater func(launcherID string) bool
// HasRenderer reports that the platform shows UI events itself. Without
// one a countdown before a rotation is skipped and the switch is made
// silently; the countdown after an exit runs either way, because a client
// may answer it.
HasRenderer bool
}
Config wires an Engine.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine is the auto-advance state machine. Create one with New. A nil *Engine accepts every call and does nothing, so callers never need to check whether it is wired.
func (*Engine) ItemLaunched ¶
ItemLaunched reports that the launch started by ItemLaunching has returned.
publishesLater says the item's launcher publishes its media itself after the launch call returns, as external lifecycle launchers do. For those the first primary media to appear in the next 30 seconds is bound to the item; for any other launcher media that did not appear during the launch is not the item's.
func (*Engine) ItemLaunching ¶
ItemLaunching reports that the launch of the item pls is on is starting. Media published until ItemLaunched is bound to the item.
func (*Engine) ItemRefused ¶
ItemRefused reports that the queue handler refused the engine's update pls because another launch was still under way. The engine tries the move again shortly, if it is still wanted.
func (*Engine) MediaEnded ¶
MediaEnded implements state.MediaObserver.
func (*Engine) MediaStarted ¶
func (e *Engine) MediaStarted(start state.MediaStart)
MediaStarted implements state.MediaObserver.
func (*Engine) NoteUserActivity ¶
func (e *Engine) NoteUserActivity()
NoteUserActivity reports a token scan or removal.
func (*Engine) PlaylistChanged ¶
PlaylistChanged reports that the playlist in slot was replaced, cleared or updated.
type Host ¶
type Host interface {
// ActivePlaylist and BackgroundPlaylist return the playlist open in each
// slot, or nil.
ActivePlaylist() *playlists.Playlist
BackgroundPlaylist() *playlists.Playlist
// ActiveMediaGeneration returns the generation of the primary media
// playing now.
ActiveMediaGeneration() (gen uint64, ok bool)
// PausePlaylistIfCurrent pauses pls in slot if it is still the open one.
PausePlaylistIfCurrent(slot string, pls *playlists.Playlist) bool
// StopSeq counts the stops of primary media Core was asked to make, once
// when each starts and again when it completes.
StopSeq() uint64
// StopInProgress reports whether a stop of the primary media is running.
StopInProgress() bool
// Enqueue sends an update to the playlist queue, giving up when ctx ends.
Enqueue(ctx context.Context, pls *playlists.Playlist) bool
}
Host is what the engine needs from the rest of the service.