Playlist for Android
Playlist
Kaltura Player provides several APIs that are used for loading, configuring, and manipulating playlists.
Load A Playlist
Before loading a playlist, you’ll need to set up a Kaltura Player instance:
val playerInitOptions = PlayerInitOptions(PARTNER_ID)
playerInitOptions.setAutoPlay(true)
player = KalturaOvpPlayer.create(this@MainActivity, playerInitOptions)
To learn how to set up a Kaltura Player, please go over this document: getting-started-android.
Once you have a Kaltura Player instance, you can load a playlist using one of the following methods:
By Playlist ID (OVP Only)
To load a playlist by ID, use OVPPlaylistIdOptions when calling loadPlaylistById
method.
val ovpPlaylistIdOptions = OVPPlaylistIdOptions()
ovpPlaylistIdOptions.playlistId = "0_w0hpzdni"
ovpPlaylistIdOptions.loopEnabled = true
player?.loadPlaylistById(ovpPlaylistIdOptions,
KalturaPlayer.OnPlaylistControllerListener() { playlistController, error ->
if (error != null) {
Snackbar.make(findViewById(android.R.id.content), error.message, Snackbar.LENGTH_LONG).show()
} else {
log.d("OVPPlaylist Loaded entry = ${playlistController.playlist.id}")
}
})
By Entry List
OVP
To load a playlist by entryId list, use OVPMediaOptions & OVPPlaylistOptions when calling loadPlaylist method.
This method creates a playlist according to the given entries.
var ovpMediaOptions1 = buildOvpMediaOptions()
var ovpMediaOptions2 = buildOvpMediaOptions()
var ovpMediaOptions3 = buildOvpMediaOptions()
var mediaList = listOf(ovpMediaOptions1, ovpMediaOptions2, ovpMediaOptions3)
val ovpPlaylistOptions = OVPPlaylistOptions()
ovpPlaylistOptions.playlistMetadata = PlaylistMetadata().setName("TestOVPPlayList").setId("2")
ovpPlaylistOptions.ovpMediaOptionsList = mediaList
ovpPlaylistOptions.playlistCountDownOptions = CountDownOptions()
player?.loadPlaylist(ovpPlaylistOptions,
KalturaPlayer.OnPlaylistControllerListener() { playlistController, error ->
if (error != null) {
Snackbar.make(findViewById(android.R.id.content), error.message, Snackbar.LENGTH_LONG).show()
} else {
log.d("OVPPlaylist Loaded entry = ${playlistController.playlist.id}")
}
})
private fun buildOvpMediaOptions(): OVPMediaOptions {
var ovpMediaAsset = OVPMediaAsset()
ovpMediaAsset.entryId = ENTRY_ID
ovpMediaAsset.ks = null
val ovpMediaOptions = OVPMediaOptions(ovpMediaAsset)
ovpMediaOptions.startPosition = START_POSITION
ovpMediaOptions.playlistCountDownOptions = CountDownOptions();
return ovpMediaOptions
}
OTT
To load a playlist by entryId list, use OVPMediaOptions
& OTTPlaylistOptions
when calling loadPlaylist
method.
This method creates a playlist according to the given entries.
var ottMediaOptions1 = buildOttMediaOptions("111111", "XXX_Main")
val ottMediaOptions2 = buildOttMediaOptions("222222", "YYY_Main")
var ottMediaOptions3 = buildOttMediaOptions("333333", "ZZZ_Main")
var mediaList = listOf(ottMediaOptions1, ottMediaOptions2, ottMediaOptions3)
val ottPlaylistIdOptions = OTTPlaylistOptions()
ottPlaylistIdOptions.playlistMetadata = PlaylistMetadata().setName("TestOTTPlayList").setId("1")
ottPlaylistIdOptions.ottMediaOptionsList = mediaList
player?.loadPlaylist(ottPlaylistIdOptions,
KalturaPlayer.OnPlaylistControllerListener() { playlistController, error ->
if (error != null) {
Snackbar.make(findViewById(android.R.id.content), error.message, Snackbar.LENGTH_LONG).show()
} else {
log.d("OTTPlaylist Loaded entry = ${playlistController.playlist.id}")
}
})
private fun buildOttMediaOptions(assetId : String, format : String): OTTMediaOptions {
val ottMediaAsset = OTTMediaAsset()
ottMediaAsset.assetId = assetId
ottMediaAsset.assetType = APIDefines.KalturaAssetType.Media
ottMediaAsset.contextType = APIDefines.PlaybackContextType.Playback
ottMediaAsset.assetReferenceType = APIDefines.AssetReferenceType.Media
ottMediaAsset.protocol = PhoenixMediaProvider.HttpProtocol.Https
ottMediaOptions.ks = null
ottMediaOptions.referrer = "app://MyTestApp";
ottMediaOptions.formats = listOf(format)
val ottMediaOptions = OTTMediaOptions(ottMediaAsset)
ottMediaOptions.startPosition = START_POSITION
return ottMediaOptions
}
By Configuration
Basic
You can load a Manual Basic playlist by configuring the playlist data and items explicitly using the configure
method.
var basicMediaOptions0 = createBasicMediaOptions("1_w9zx2eti1", SOURCE_URL, CountDownOptions(50000, 10000, true))
val basicMediaOptions1 = createBasicMediaOptions("0_uka1msg4", SOURCE_URL2, CountDownOptions(10000, true))
var basicMediaOptions2 = createBasicMediaOptions("1_w9zx2eti2", SOURCE_URL, CountDownOptions())
var basicMediaOptionsList = listOf(basicMediaOptions0, basicMediaOptions1, basicMediaOptions2)
val basicPlaylistIdOptions = BasicPlaylistOptions()
basicPlaylistIdOptions.playlistMetadata = PlaylistMetadata().setName("TestBasicPlayList").setId("1")
basicPlaylistIdOptions.basicMediaOptionsList = basicMediaOptionsList
player?.loadPlaylist(basicPlaylistIdOptions,
KalturaPlayer.OnPlaylistControllerListener() { playlistController, error ->
if (error != null) {
Snackbar.make(findViewById(android.R.id.content), error.message, Snackbar.LENGTH_LONG).show()
} else {
log.d("BasicPlaylist Loaded entry = ${playlistController.playlist.id}")
}
})
private fun createBasicMediaOptions(id: String, url : String, countdownOptions: CountDownOptions): BasicMediaOptions {
val mediaEntry = PKMediaEntry()
mediaEntry.id = id
mediaEntry.mediaType = PKMediaEntry.MediaEntryType.Vod
val mediaSources = createMediaSources(id, url)
mediaEntry.sources = mediaSources
return BasicMediaOptions(mediaEntry, countdownOptions)
}
Configure the Playlist
Playlist Options
Playlist Metadata - playlistMetadata
Should be used for all Playlists except the OVP by id configuration where this data is retrieved from the BE.
Start Index - startIndex
The index that the playlist playback should start from (default index = 0)
Loop - loopEnabled
The playlist will play the first media in the playlist once the last media in the playlist has ended (default false)
Auto Continue -autoContinue
The next media in the playlist will be played automatically once the previous media ended (default true)
Recover On Error - recoverOnError
The playlist manager is able to recover from errors once that flag is enabled, so it will continue to the next media whether the current media is incorrect or it’s URL is broken. If auto continue is enabled it will auto play without user intervention.
Count Down Options - playlistCountDownOptions
The logic by which count down start event will be fired (default is 10 last sec for 10 sec).
if autoContinue
feature is enabled at the end of the count down the PlaylistController
will trigger auto continue feature to play next media. If auto continue == false countdown will events will not be fired.
If loop
is disabled the events will not be fired for last media.
Use API Captions - useApiCaptions
used only for OVP configuration this can be configured on the playlist level or media level
To change this behavior, configure the playlist options using one of the following methods:
Via the API:
Example:
// OVPPlaylistIdOptions
val ovpPlaylistIdOptions = OVPPlaylistIdOptions()
ovpPlaylistIdOptions.playlistId = "zzzzzzz"
ovpPlaylistIdOptions.startIndex = 0
ovpPlaylistIdOptions.ks = ""
ovpPlaylistIdOptions.playlistCountDownOptions = CountDownOptions()
ovpPlaylistIdOptions.useApiCaptions = false
ovpPlaylistIdOptions.loopEnabled = false
ovpPlaylistIdOptions.autoContinue = true
ovpPlaylistIdOptions.recoverOnError = false
// OVPPlaylistOptions
val ovpPlaylistOptions = OVPPlaylistOptions()
ovpPlaylistOptions.startIndex = 0
ovpPlaylistOptions.ks = ""
ovpPlaylistOptions.playlistCountDownOptions = CountDownOptions()
ovpPlaylistOptions.playlistMetadata = PlaylistMetadata().setName("TestOTTPlayList").setId("1")
ovpPlaylistOptions.ovpMediaOptionsList = ovpMediaOptionsList //(useApiCaptions is configured for each media separetly)
ovpPlaylistOptions.loopEnabled = false
ovpPlaylistOptions.autoContinue = true
ovpPlaylistOptions.recoverOnError = false
// OVPPlaylistOptions
val ottPlaylistIdOptions = OTTPlaylistOptions()
ottPlaylistIdOptions.startIndex = 0
ottPlaylistIdOptions.playlistCountDownOptions = CountDownOptions()
ottPlaylistIdOptions.playlistMetadata = PlaylistMetadata().setName("TestOTTPlayList").setId("1")
ottPlaylistIdOptions.ottMediaOptionsList = ottMediaOptionsList
ottPlaylistIdOptions.loopEnabled = false
ottPlaylistIdOptions.autoContinue = true
ottPlaylistIdOptions.recoverOnError = false
// BasicPlaylistOptions
val basicPlaylistIdOptions = BasicPlaylistOptions()
basicPlaylistIdOptions.startIndex = 0
basicPlaylistIdOptions.playlistMetadata = PlaylistMetadata().setName("TestBasicPlayList").setId("1")
basicPlaylistIdOptions.playlistCountDownOptions = CountDownOptions()
basicPlaylistIdOptions.basicMediaOptionsList = basicMediaOptionsList
basicPlaylistIdOptions.loopEnabled = false
basicPlaylistIdOptions.autoContinue = true
basicPlaylistIdOptions.recoverOnError = false
Note: The
autoContinue
property is relevant only for the second item onwards.
To control the first entry playback, set theautoPlay
property to the desired value (default = true).
Playlist Count Countdown Options
When the current item is about to end and the playlist is set to continue automatically by setting autoContinue = true
, the application will get countdown start event. Then the application can display up next or watch credits pop up.
Once countdown is over, countdown ended event will be fired.
Using the disableCountDown
API, application can cancel the current countdown configuration, so it will not be executed and the PlaylistController
will not trigger the playNext
API.
Example:
player?.playlistController?.disableCountDown()
By default, the countdown is fired at the last 10 media seconds for the last 10 seconds of the media.
The CountDownOptions
timeToShow
and duration
values are presented in milliseconds.
To change this behavior, configure the CountDownOptions
For example, to show the countdown for 20 seconds until the end, configure:
Via the API:
OVP by id - exists only for the playlist level.
ovpPlaylistIdOptions.playlistCountDownOptions = CountDownOptions(20000, true)
OVP/OTT by entries list - exists both on playlist level or media level.
ovpPlaylistOptions.playlistCountDownOptions = CountDownOptions(10000, true)
ovpMediaOptions.playlistCountDownOptions = CountDownOptions(90000, 10000, true);
By configuration:
Available for playlist level or media level
basicPlaylistIdOptions.countDownOptions = CountDownOptions(5000, true)
createBasicMediaOptions(0,"1_w9zx2eti1", SOURCE_URL, CountDownOptions(60000, 10000, true))
Note:
Once the playlistCountDownEnd
event is fired, the next media entry in the playlist a will be played.
PlaylistController Interface
Once playlist is loaded the callback will return a controller object the can be used to control the playlist life cycle from the application perspective.
Another option to get a reference to the controller, is to
call player?.playlistController
with the required API from the interface after the playlist is loaded.
public interface PlaylistController {
/**
* getPlaylist - get current playlist data
*
* @return - PKPlaylist
*/
PKPlaylist getPlaylist();
/**
* getPlaylistType - get current playlist type OVP_ID,OVP_LIST,OTT_LIST,BASIC_LIST
*
* @return - PKPlaylistType
*/
PKPlaylistType getPlaylistType();
/**
* getCurrentPlaylistMedia - get current playlist media data.
*
* @return - PKPlaylistMedia
*/
PKPlaylistMedia getCurrentPlaylistMedia();
/**
* getCurrentMediaIndex for current playing media.
*
* @return - int
*/
int getCurrentMediaIndex();
/**
* GetCurrentCountDownOptions for current media.
*
* @return - CountDownOptions
*/
CountDownOptions getCurrentCountDownOptions();
/**
* DisableCountDown for current media.
*
*/
void disableCountDown();
/**
* Preload next item - will do the provider request for specific media to save network calls not relevant for basic player.
*
*/
void preloadNext();
/**
* PreloadItem by index - will do the provider request for specific media to save network calls not relevant for basic player.
*
* @param index - media index in playlist.
*/
void preloadItem(int index);
/**
* PlayItem by index.
*
* @param index - media index in playlist.
*/
void playItem(int index);
/**
* PlayItem by index and auto play configuration.
*
* @param index - media index in playlist.
* @param isAutoPlay - isAutoPlay.
*/
void playItem(int index, boolean isAutoPlay);
/**
* playNext - play the next media in the playlist.
*
*/
void playNext();
/**
* playPrev - play the previous media in the playlist.
*
*/
void playPrev();
/**
* replay - play the playlist from the first index.
*
*/
void replay();
/**
* isMediaLoaded - validation if media was fetched/played at least one time so the playback information is available.
*
* @param mediaId - media id in playlist.
* @return - boolean
*/
boolean isMediaLoaded(String mediaId);
/**
* setLoop - configure the controller to play the playlist again
* when last playlist media is ended
*
* @param mode - enabled/disabled.
*/
void setLoop(boolean mode);
/**
* isLoopEnabled - validation if playlist controller is configured to support setLoop mode.
*
* @return - boolean
*/
boolean isLoopEnabled();
/**
* setAutoContinue - configure the controller to play the playlist in setAutoContinue mode
*
* @param mode - enabled/disabled.
*/
void setAutoContinue(boolean mode);
/**
* isAutoContinueEnabled - validation if playlist controller is configured to support setAutoContinue mode.
*
* @return - boolean
*/
boolean isAutoContinueEnabled();
/**
* setRecoverOnError - ignore media playback errors and continue
*
* @param mode - enabled/disabled.
*/
void setRecoverOnError(boolean mode);
/**
* isRecoverOnError - validation if playlist controller should recover on error.
*
* @return - boolean
*/
boolean isRecoverOnError();
/**
* release - should e called if we want to reuse the player for single media or for loading new play list.
*/
void release();
/**
* setPlaylistOptions - configure the controller with the initial playlist options
*
* @param playlistOptions - playlist initial configuration.
*/
void setPlaylistOptions(PlaylistOptions playlistOptions);
/**
* setPlaylistCountDownOptions - update the current playlist countdown configuration
*
* @param playlistCountDownOptions - playlist countdown.
*/
void setPlaylistCountDownOptions(@Nullable CountDownOptions playlistCountDownOptions);
}
##Playlist Navigation
Using the PlaylistController
API, you can get the playlist data and then switch between the items.
// switch to the next item
player?.playlistController?.playNext()
// switch to the previous item
player?.playlistController?.playPrev()
// switch to a specific item by index
player?.playlistController?.playItem(2)
Change Playlist
To clean the playlist data, you’ll need to call the playlist controller release()
API
Here is an example for how it is possible to change the playlist using the release
method when previous playlist ended.
player?.addListener(this, PlaylistEvent.playListEnded) { event ->
log.d("PLAYLIST playListEnded")
ovpPlaylistIdOptions.playlistId = "0_jco198ds"
player?.loadPlaylistById(ovpPlaylistIdOptions) { playlistController, error ->
if (error != null) {
Snackbar.make(findViewById(android.R.id.content), error.message, Snackbar.LENGTH_LONG).show()
} else {
playbackControlsManager?.addChangeMediaImgButtonsListener(playlistController.playlist.mediaListSize)
}
}
}
}
Playlist Events
Application can add listeners to the following events
using these events application can react to UI changes for example.
These events are defined in PlaylistEvent
class.
Please check the class for the event payload.
public enum Type {
PLAYLIST_LOADED,
PLAYLIST_STARTED,
PLAYLIST_ENDED,
PLAYLIST_COUNT_DOWN_START,
PLAYLIST_COUNT_DOWN_END,
PLAYLIST_LOOP_STATE_CHANGED,
PLAYLIST_SUFFLE_STATE_CHANGED,
PLAYLIST_AUTO_CONTINUE_STATE_CHANGED,
PLAYLIST_ERROR,
PLAYLIST_LOAD_MEDIA_ERROR
}
player?.addListener(this, PlaylistEvent.playListLoaded) { event ->
log.d("playListLoaded " + event.playlist.name)
}
player?.addListener(this, PlaylistEvent.playListStarted) { event ->
log.d("playListStarted " + event.playlist.name)
}
player?.addListener(this, PlaylistEvent.playListEnded) { event ->
log.d("PlaylistEnded " + event.playlist.name)
}
player?.addListener(this, PlaylistEvent.playlistCountDownStart) { event ->
log.d("playlistCountDownStart currentPlayingIndex = " + event.currentPlayingIndex + " durationMS = " + event.playlistCountDownOptions.durationMS);
}
player?.addListener(this, PlaylistEvent.playlistCountDownEnd) { event ->
log.d("playlistCountDownEnd currentPlayingIndex = " + event.currentPlayingIndex + " durationMS = " + event.playlistCountDownOptions.durationMS);
}
player?.addListener(this, PlaylistEvent.playlistLoopStateChanged) { event ->
log.d("playlistLoopStateChanged " + event.mode);
}
player?.addListener(this, PlaylistEvent.playlistAutoContinueStateChanged) { event ->
log.d("PLAYLIST playlistAutoContinueStateChanged " + event.mode)
}
player?.addListener(this, PlaylistEvent.playListError) { event ->
log.d("playListError = " + event.error.message);
}
player?.addListener(this, PlaylistEvent.playlistLoadMediaError) { event ->
log.d("playListMediaError = " + event.error.message);
}