Package com.castlabs.android.player.playlist

# Class MultiControllerPlaylist

java.lang.Object
com.castlabs.android.player.AbstractPlayerListener
com.castlabs.android.player.playlist.MultiControllerPlaylist

All Implemented Interfaces:
  `PlayerListener`, `PlayerViewLifecycleDelegate.LifecycleListener`, `Playlist`

Direct Known Subclasses:
  `PlaylistController`

public class MultiControllerPlaylist extends AbstractPlayerListener implements PlayerViewLifecycleDelegate.LifecycleListener, Playlist
Playlist management. Use this class if you want to have playlist-like behaviour.

In order to use it, you should create an instance, initializing it with a `PlayerView` or just a `Context` in case you are using a custom View. Then, playback is started through the `open(PlayerConfig...)` method, which takes a list of items to play consecutively.

For the sake of completely seamless Playlist item transitions, this class uses two underlying `PlayerControllers`, preparing one shortly before the current item reaches the end.

You should also register a `MultiControllerPlaylist.PlaylistListener` in the constructor to get Playlist-specific events, such as when a Playlist item change occurs. It's important to add the corresponding unbinding and binding logic here for the old and new `PlayerControllers` respectively.

The current Playlist can be obtained with `getPlaylist()` and the current item with `getCurrentItem()`. The MultiControllerPlaylist operates on `PlayerConfig` objects.

This class provides methods to manage the Playlist:

- `addItem(PlayerConfig)`
- `addItem(int, PlayerConfig)`
- `removeItem(PlayerConfig)`
- `swap(PlayerConfig, PlayerConfig)`
- `slideNext()`
- `slidePrevious()`

The MultiControllerPlaylist allows for some configuration. The `setNextItemThreshold(int)` method allows to set how much time before the end of an asset should the next playlist item be prepared. Looping can be enabled with `enableLooping(boolean)`. Looping will result in playback starting over from the first Playlist item once the last finishes.

Both these settings are dynamic, and will take effect immediately for the following Playlist item.

Playback behaviour of live content items is undefined.

Since:
  4.2.5

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `static class`
  `MultiControllerPlaylist.AbstractPlaylistListener`
  Abstract implementation of the `MultiControllerPlaylist.PlaylistListener`.
  `static final class`
  `MultiControllerPlaylist.Builder`
  Builder for `MultiControllerPlaylist`
  `static @interface`
  `MultiControllerPlaylist.ItemChangeFlags`
  `static interface`
  `MultiControllerPlaylist.PlaylistListener`
  Playlist-related events listener.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final int`
  `DEFAULT_ITEM_CHANGE_FLAGS`
  Default behaviour when it comes to item change.
  `static final int`
  `ITEM_THRESHOLD_FULLY_BUFFERED`
  Default value for `setNextItemThreshold(int)`.
  `static final int`
  `ITEM_THRESHOLD_UPON_START`
  The value to be set in `setNextItemThreshold(int)` indicating the next stream should be prepared together with the current stream
  `static final int`
  `KEEP_ALL`
  Flag which indicates to carry all the track selections and bandwidth estimate from one PlayerController onto the next one, as well as the `TrickplayConfiguration`.
  `static final int`
  `KEEP_AUDIO_TRACK`
  Flag which indicates to carry the selected `AudioTrack` from one PlayerController onto the next one.
  `static final int`
  `KEEP_BANDWIDTH_ESTIMATE`
  Flag which indicates to carry the last available bitrate estimate from one PlayerController onto the next one.
  `static final int`
  `KEEP_SUBTITLE_TRACK`
  Flag which indicates to carry the selected `SubtitleTrack` from one PlayerController onto the next one.
  `static final int`
  `KEEP_TRICKPLAY_CONFIG`
  Flag which indicates to carry the current `TrickplayConfiguration` from one PlayerController onto the next one.
  `static final int`
  `KEEP_VIDEO_QUALITY`
  Flag which indicates to carry the selected `VideoTrackQuality` from one PlayerController onto the next one.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `MultiControllerPlaylist(Context context, MultiControllerPlaylist.PlaylistListener listener)`
  Deprecated.
  Use the `Builder`.
  `MultiControllerPlaylist(PlayerView playerView, MultiControllerPlaylist.PlaylistListener listener)`
  Deprecated.
  Use the `Builder`.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addItem(int position, PlayerConfig config)`
  Adds an item at the specified position in the playlist.
  `void`
  `addItem(PlayerConfig config)`
  Adds an item at the end of the playlist.
  `void`
  `enableLooping(boolean enableLooping)`
  Whether to enable Playlist looping or not.
  `PlayerController`
  `getCurrentController()`
  Returns the current underlying `PlayerController`.
  `PlayerConfig`
  `getCurrentItem()`
  Returns the currently playing item
  `int`
  `getCurrentItemIndex()`
  Returns current item index
  `Collection<PlayerConfig>`
  `getLoadedConfigs()`
  `List<PlayerConfig>`
  `getPlaylist()`
  Returns the current Playlist as a List of `PlayerConfig` items.
  `int`
  `getSize()`
  Returns the number of Configs in the playlist.
  `static void`
  `migratePlayerListeners(PlayerController oldController, PlayerController newController)`
  Deprecated.
  Use `PlayerController.movePlayerListeners(PlayerController)`
  `PlayerConfig`
  `nextItem()`
  Advances playback to the next Playlist item.
  `void`
  `onBeforeRelease(boolean backgroundPlayback)`
  `void`
  `onError(CastlabsPlayerException error)`
  Error callback that is called when exceptions are raised on background threads.
  `void`
  `onFatalErrorOccurred(CastlabsPlayerException error)`
  Error callback that is called when a fatal exception is raised on background threads.
  `void`
  `onFullyBuffered()`
  Invoked when all the remaining content has been buffered.
  `void`
  `onPlaybackPositionChanged(long playbackPositionMs)`
  Event triggered when the playback position changed.
  `void`
  `onPostDestroy()`
  `void`
  `onPostRelease(boolean backgroundPlayback)`
  `void`
  `onPostResume(PlayerController playerController)`
  `void`
  `onPostStart()`
  `void`
  `onSeekRangeChanged(long startTimeMs, long endTimeMs)`
  Event triggered when the seek range changed
  `void`
  `onSeekTo(long newPosition)`
  This callback is invoked when the position of the video playback is actively changed by the `PlayerController`.
  `void`
  `onStateChanged(PlayerController.State state)`
  State change event triggered when the player state changed
  `void`
  `onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio)`
  Invoked each time there's a change in the size of the video being rendered.
  `void`
  `open(int startIndex, Parcelable... playerConfigs)`
  Start playback with the specified index and with an Array of `PlayerConfigs` or `Bundles`.
  `void`
  `open(int startIndex, List<? extends Parcelable> playerConfigs)`
  Start playback with the specified index and player configs
  `void`
  `open(Bundle... bundles)`
  Starts playback with an Array of Bundles.
  `void`
  `open(Parcelable... playerConfigs)`
  Starts playback with an Array of `PlayerConfigs` or `Bundles`.
  `void`
  `open(PlayerConfig... playerConfigs)`
  Starts playback with an Array of `PlayerConfigs`.
  `void`
  `open(List<? extends Parcelable> playerConfigs)`
  Starts playback with a List of `PlayerConfigs` or `Bundles`.
  `PlayerConfig`
  `playItem(int index)`
  Advances playback to the Playlist item specified by the index.
  `PlayerConfig`
  `previousItem()`
  Moves backwards in the Playlist.
  `void`
  `removeItem(PlayerConfig config)`
  Removes an item from the Playlist
  `void`
  `setItemChangeFlags(int flags)`
  Sets the behaviour that will be applied when a new playlist item is about to be played.
  `void`
  `setNextItemThreshold(int nextItemThresholdMs)`
  `void`
  `slideNext()`
  Slides the current item in the playlist to the next position.
  `void`
  `slidePrevious()`
  Slides the current item in the playlist to the previous position.
  `void`
  `swap(PlayerConfig playerConfig1, PlayerConfig playerConfig2)`
  Interchanges two Playlist items.

  ### Methods inherited from class com.castlabs.android.player.AbstractPlayerListener

  `onDisplayChanged, onDurationChanged, onPlayerModelChanged, onSeekCompleted, onSpeedChanged, onVideoKeyStatusChanged`

  ### Methods inherited from class java.lang.Object

  `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### ITEM_THRESHOLD_FULLY_BUFFERED

    public static final int ITEM_THRESHOLD_FULLY_BUFFERED
    Default value for `setNextItemThreshold(int)`. This is a special value indicating that the next `PlayerController` should be prepared as soon as the current one is done loading data. This corresponds to the `PlayerListener.onFullyBuffered()` method.
    See Also:
      - Constant Field Values

  - ### ITEM_THRESHOLD_UPON_START

    public static final int ITEM_THRESHOLD_UPON_START
    The value to be set in `setNextItemThreshold(int)` indicating the next stream should be prepared together with the current stream
    See Also:
      - Constant Field Values

  - ### KEEP_BANDWIDTH_ESTIMATE

    public static final int KEEP_BANDWIDTH_ESTIMATE
    Flag which indicates to carry the last available bitrate estimate from one PlayerController onto the next one. This will allow playback to continue in the same (or closest) possible quality, if ABR is enabled.
    See Also:
      - Constant Field Values

  - ### KEEP_VIDEO_QUALITY

    public static final int KEEP_VIDEO_QUALITY
    Flag which indicates to carry the selected `VideoTrackQuality` from one PlayerController onto the next one. Video quality matching will be made exclusively by their `bitrate`. If no matching quality is found, the one with the closest bitrate will be selected.
    See Also:
      - Constant Field Values

  - ### KEEP_AUDIO_TRACK

    public static final int KEEP_AUDIO_TRACK
    Flag which indicates to carry the selected `AudioTrack` from one PlayerController onto the next one. Track matching is based solely on their `language`.
    See Also:
      - Constant Field Values

  - ### KEEP_SUBTITLE_TRACK

    public static final int KEEP_SUBTITLE_TRACK
    Flag which indicates to carry the selected `SubtitleTrack` from one PlayerController onto the next one. Track matching is based solely on their `language`.
    See Also:
      - Constant Field Values

  - ### KEEP_TRICKPLAY_CONFIG

    public static final int KEEP_TRICKPLAY_CONFIG
    Flag which indicates to carry the current `TrickplayConfiguration` from one PlayerController onto the next one. Current Trickplay enabled state (`PlayerController.enableTrickplayMode(boolean)` will also be carried over.
    Since:
      4.2.4
    See Also:
      - Constant Field Values

  - ### KEEP_ALL

    public static final int KEEP_ALL
    Flag which indicates to carry all the track selections and bandwidth estimate from one PlayerController onto the next one, as well as the `TrickplayConfiguration`.
    See Also:
      - Constant Field Values

  - ### DEFAULT_ITEM_CHANGE_FLAGS

    public static final int DEFAULT_ITEM_CHANGE_FLAGS
    Default behaviour when it comes to item change.
    See Also:
      - Constant Field Values

- ## Constructor Details

  - ### MultiControllerPlaylist

    public MultiControllerPlaylist(@NonNull PlayerView playerView, @Nullable MultiControllerPlaylist.PlaylistListener listener)
    Deprecated.
    Use the `Builder`.
    Constructor which takes a `PlayerView`. If you're not using it, or have a custom UI, use the `MultiControllerPlaylist(Context, PlaylistListener)` constructor instead.
    Parameters:
      `playerView` - PlayerView to bind the PlayerController. If it already has a `PlayerController`, it will be ignored and replaced with a new one.
      `listener` - a `MultiControllerPlaylist.PlaylistListener` to be informed about Playlist events.

  - ### MultiControllerPlaylist

    public MultiControllerPlaylist(@NonNull Context context, @Nullable MultiControllerPlaylist.PlaylistListener listener)
    Deprecated.
    Use the `Builder`.
    Parameters:
      `context` - the Context used to create the PlayerControllers.
      `listener` - a `MultiControllerPlaylist.PlaylistListener` to be informed about Playlist events.

- ## Method Details

  - ### getLoadedConfigs

    public Collection<PlayerConfig> getLoadedConfigs()

  - ### migratePlayerListeners

    public static void migratePlayerListeners(@Nullable PlayerController oldController, @Nullable PlayerController newController)
    Deprecated.
    Use `PlayerController.movePlayerListeners(PlayerController)`
    Migrates all the listeners from one PlayerController to the other. Typical usage of this method is in an implementation of `MultiControllerPlaylist.PlaylistListener.onItemChange(PlayerConfig, PlayerController, PlayerController)`.
    Parameters:
      `oldController` - the PlayerController where to get and remove the listeners from
      `newController` - the PlayerController where to set the listeners to

  - ### enableLooping

    public void enableLooping(boolean enableLooping)
    Whether to enable Playlist looping or not. If enabled, playback will carry on to the first Playlist item one the last one finishes. It can also have an effect with methods such as `nextItem()` and `slideNext()`.
    Parameters:
      `enableLooping` - whether to enable Playlist looping or not

  - ### setNextItemThreshold

    public void setNextItemThreshold(int nextItemThresholdMs)
    Parameters:
      `nextItemThresholdMs` - how much time before the end of an asset should the next Playlist item be prepared, in milliseconds. Default value is `ITEM_THRESHOLD_FULLY_BUFFERED`, see also `ITEM_THRESHOLD_UPON_START`

  - ### setItemChangeFlags

    public void setItemChangeFlags(int flags)
    Sets the behaviour that will be applied when a new playlist item is about to be played.

    The MultiControllerPlaylist can take care of carrying some configuration to the new PlayerController, especially related to currently selected tracks.

    Takes effect immediately, if changed mid-playback, the flags will be evaluated on the next item change.

    You should ideally call this method right after MultiControllerPlaylist creation.

    Parameters:
      `flags` - flags to set.
    See Also:
      - `MultiControllerPlaylist.ItemChangeFlags`

  - ### onPostStart

    public void onPostStart()
    Specified by:
      `onPostStart` in interface `PlayerViewLifecycleDelegate.LifecycleListener`

  - ### onPostResume

    public void onPostResume(@NonNull PlayerController playerController)
    Specified by:
      `onPostResume` in interface `PlayerViewLifecycleDelegate.LifecycleListener`

  - ### onBeforeRelease

    public void onBeforeRelease(boolean backgroundPlayback)
    Specified by:
      `onBeforeRelease` in interface `PlayerViewLifecycleDelegate.LifecycleListener`

  - ### onPostRelease

    public void onPostRelease(boolean backgroundPlayback)
    Specified by:
      `onPostRelease` in interface `PlayerViewLifecycleDelegate.LifecycleListener`

  - ### onPostDestroy

    public void onPostDestroy()
    Specified by:
      `onPostDestroy` in interface `PlayerViewLifecycleDelegate.LifecycleListener`

  - ### open

    public void open(@NonNull Parcelable... playerConfigs)
    Description copied from interface: `Playlist`
    Starts playback with an Array of `PlayerConfigs` or `Bundles`.

    The playlist might apply some generic configuration to the items passed to this method. This implies that the items in the playlist *won't necessarily be the same instances*.

    Specified by:
      `open` in interface `Playlist`
    Parameters:
      `playerConfigs` - array of PlayerConfigs or Bundles, each representing a Playlist item.

  - ### open

    public void open(int startIndex, @NonNull Parcelable... playerConfigs)
    Description copied from interface: `Playlist`
    Start playback with the specified index and with an Array of `PlayerConfigs` or `Bundles`.

    The playlist might apply some generic configuration to the items passed to this method. This implies that the items in the playlist *won't necessarily be the same instances*.

    Specified by:
      `open` in interface `Playlist`
    Parameters:
      `startIndex` - The index of the config to start playback with
      `playerConfigs` - The array of player configs to play

  - ### open

    public void open(@NonNull Bundle... bundles)
    Starts playback with an Array of Bundles. Refer to `PlayerController.open(Bundle)` to see the supported keys.
    Parameters:
      `bundles` - array of Bundles, each representing a Playlist item.

  - ### open

    public void open(@NonNull PlayerConfig... playerConfigs)
    Starts playback with an Array of `PlayerConfigs`.
    Parameters:
      `playerConfigs` - array of PlayerConfigs, each representing a Playlist item.

  - ### open

    public void open(@NonNull List<? extends Parcelable> playerConfigs)
    Description copied from interface: `Playlist`
    Starts playback with a List of `PlayerConfigs` or `Bundles`.

    The playlist might apply some generic configuration to the items passed to this method. This implies that the items in the playlist *won't necessarily be the same instances*.

    Specified by:
      `open` in interface `Playlist`
    Parameters:
      `playerConfigs` - list of PlayerConfigs, or Bundles each representing a Playlist item.

  - ### open

    public void open(int startIndex, @NonNull List<? extends Parcelable> playerConfigs)
    Description copied from interface: `Playlist`
    Start playback with the specified index and player configs

    The playlist might apply some generic configuration to the items passed to this method. This implies that the items in the playlist *won't necessarily be the same instances*.

    Specified by:
      `open` in interface `Playlist`
    Parameters:
      `startIndex` - The index of the config to start playback with
      `playerConfigs` - The list of player configs to play

  - ### getCurrentController

    @NonNull public PlayerController getCurrentController()
    Returns the current underlying `PlayerController`. If there's currently no playing media, a Controller will be created and returned.
    Returns:
      the current underlying PlayerController.

  - ### getPlaylist

    public List<PlayerConfig> getPlaylist()
    Returns the current Playlist as a List of `PlayerConfig` items.
    Specified by:
      `getPlaylist` in interface `Playlist`
    Returns:
      the current Playlist

  - ### getSize

    public int getSize()
    Description copied from interface: `Playlist`
    Returns the number of Configs in the playlist.
    Specified by:
      `getSize` in interface `Playlist`
    Returns:
      number of Configs

  - ### getCurrentItem

    public PlayerConfig getCurrentItem()
    Returns the currently playing item
    Specified by:
      `getCurrentItem` in interface `Playlist`
    Returns:
      the currently playing item

  - ### getCurrentItemIndex

    public int getCurrentItemIndex()
    Description copied from interface: `Playlist`
    Returns current item index
    Specified by:
      `getCurrentItemIndex` in interface `Playlist`
    Returns:
      Current item index or `-1` otherwise

  - ### addItem

    public void addItem(@NonNull PlayerConfig config)
    Description copied from interface: `Playlist`
    Adds an item at the end of the playlist.
    Specified by:
      `addItem` in interface `Playlist`
    Parameters:
      `config` - item to add

  - ### addItem

    public void addItem(int position, @NonNull PlayerConfig config)
    Adds an item at the specified position in the playlist.
    Specified by:
      `addItem` in interface `Playlist`
    Parameters:
      `position` - the position at which to add the item.
      `config` - item to add
    Throws:
      `IndexOutOfBoundsException` - if the position is negative or greater than the current Playlist size.

  - ### removeItem

    public void removeItem(@NonNull PlayerConfig config)
    Removes an item from the Playlist
    Specified by:
      `removeItem` in interface `Playlist`
    Parameters:
      `config` - item to remove

  - ### swap

    public void swap(@NonNull PlayerConfig playerConfig1, @NonNull PlayerConfig playerConfig2)
    Interchanges two Playlist items. If any of such items is the currently playing item, playback won't be affected.
    Specified by:
      `swap` in interface `Playlist`
    Parameters:
      `playerConfig1` - first item to swap
      `playerConfig2` - second item to swap

  - ### slideNext

    public void slideNext()
    Slides the current item in the playlist to the next position. If the current item is the last in the playlist, will be set to the first one only if `looping` is enabled.

  - ### slidePrevious

    public void slidePrevious()
    Slides the current item in the playlist to the previous position. If the current item is the fist in the playlist, will be set to the last one only if `looping` is enabled.

  - ### onFatalErrorOccurred

    public void onFatalErrorOccurred(@NonNull CastlabsPlayerException error)
    Description copied from interface: `PlayerListener`
    Error callback that is called when a fatal exception is raised on background threads. All Exceptions are wrapped in a `CastlabsPlayerException`. This method will be invoked *only* for fatal errors, and *before* the PlayerController is `released`. The `PlayerListener.onError(CastlabsPlayerException)` method will be invoked after this one.
    Specified by:
      `onFatalErrorOccurred` in interface `PlayerListener`
    Overrides:
      `onFatalErrorOccurred` in class `AbstractPlayerListener`
    Parameters:
      `error` - the player exception

  - ### onError

    public void onError(@NonNull CastlabsPlayerException error)
    Description copied from interface: `PlayerListener`
    Error callback that is called when exceptions are raised on background threads. All Exceptions are wrapped in a `CastlabsPlayerException`. If the error is `fatal`, the PlayerController will be `released` right before this callback.
    Specified by:
      `onError` in interface `PlayerListener`
    Overrides:
      `onError` in class `AbstractPlayerListener`
    Parameters:
      `error` - the player exception

  - ### onStateChanged

    public void onStateChanged(@NonNull PlayerController.State state)
    Description copied from interface: `PlayerListener`
    State change event triggered when the player state changed
    Specified by:
      `onStateChanged` in interface `PlayerListener`
    Overrides:
      `onStateChanged` in class `AbstractPlayerListener`
    Parameters:
      `state` - the new state

  - ### nextItem

    @Nullable public PlayerConfig nextItem()
    Advances playback to the next Playlist item. This is affected by `looping`.
    Specified by:
      `nextItem` in interface `Playlist`
    Returns:
      the next item to play. If null, the end of the Playlist has been reached.

  - ### playItem

    @Nullable public PlayerConfig playItem(int index)
    Description copied from interface: `Playlist`
    Advances playback to the Playlist item specified by the index.
    Specified by:
      `playItem` in interface `Playlist`
    Returns:
      the item to play. If null, the end of the Playlist has been reached.

  - ### previousItem

    @Nullable public PlayerConfig previousItem()
    Moves backwards in the Playlist. This is affected by `looping`.
    Specified by:
      `previousItem` in interface `Playlist`
    Returns:
      the next item to play. If null, the start of the Playlist has been reached.

  - ### onSeekTo

    public void onSeekTo(long newPosition)
    Description copied from interface: `PlayerListener`
    This callback is invoked when the position of the video playback is actively changed by the `PlayerController`.
    Specified by:
      `onSeekTo` in interface `PlayerListener`
    Overrides:
      `onSeekTo` in class `AbstractPlayerListener`
    Parameters:
      `newPosition` - the new position in microseconds

  - ### onVideoSizeChanged

    public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio)
    Description copied from interface: `PlayerListener`
    Invoked each time there's a change in the size of the video being rendered.
    Specified by:
      `onVideoSizeChanged` in interface `PlayerListener`
    Overrides:
      `onVideoSizeChanged` in class `AbstractPlayerListener`
    Parameters:
      `width` - The video width in pixels.
      `height` - The video height in pixels.
      `pixelWidthHeightRatio` - The width to height ratio of each pixel. For the normal case of square pixels this will be equal to 1.0. Different values are indicative of anamorphic content.

  - ### onSeekRangeChanged

    public void onSeekRangeChanged(long startTimeMs, long endTimeMs)
    Description copied from interface: `PlayerListener`
    Event triggered when the seek range changed
    Specified by:
      `onSeekRangeChanged` in interface `PlayerListener`
    Overrides:
      `onSeekRangeChanged` in class `AbstractPlayerListener`
    Parameters:
      `startTimeMs` - the possible seek start time in milliseconds
      `endTimeMs` - the possible seek end time in milliseconds

  - ### onPlaybackPositionChanged

    public void onPlaybackPositionChanged(long playbackPositionMs)
    Description copied from interface: `PlayerListener`
    Event triggered when the playback position changed. Note that for performance reasons, this is triggered at most once per second, hence you will only see when seconds changing during playback.
    Specified by:
      `onPlaybackPositionChanged` in interface `PlayerListener`
    Overrides:
      `onPlaybackPositionChanged` in class `AbstractPlayerListener`
    Parameters:
      `playbackPositionMs` - the current playback position in milliseconds

  - ### onFullyBuffered

    public void onFullyBuffered()
    Description copied from interface: `PlayerListener`
    Invoked when all the remaining content has been buffered. From this point onwards no more network activity is required to finish playing the current media.
    Specified by:
      `onFullyBuffered` in interface `PlayerListener`
    Overrides:
      `onFullyBuffered` in class `AbstractPlayerListener`