Resume Point API
What you learn​
You are instantiating DIVA Player in your Roku application and relying on DIVA Back Office as the video streaming source.
The goal of this article is to build the simplest Roku app to stream a video from the DIVA Back Office and how to work with Resume Point API
.
Resume Point API
will notify the subscriber about a change and also allow the integrator to query the current status Diva Player.
Before starting​
- Ensure
Diva Player lib
andDIVA Back Office Adapter lib
downloaded (Setup > Step 13). - Ask your video engineers team the
<video id>
and<settings URL>
.
Technical Details
Resume Point API
helps integrator to get updates of: Player Position
, Video Metadata
and Player State
-
Player Position
- value triggered constantly while video is playing. It will emit a structure which contains:relativePosition
is formatted as millisecond integer numberabsolutePosition
is formatted as a date (logged as ISO format)
-
Video Metadata
- Exposes the VideoMetadata received by Diva via VideoMetaDataProvider. From here integrator can know which video is being player, video id may be used to identify the current video being played. It is important because Diva can internally change the video being played, for instance thought video list or end of play. -
Player State
- The current player state should inform the current player state. At a minimum, it should contain playing and pause. The integrator may save the resume point when the user pauses the video.Variants of the state that can comes from Diva Player:
inited
- this event triggers when Diva Player finished the initializationstarted
- when video playback startedbuffering
- video stream in the buffering stateplaying
- video stream are playingpaused
- video stream pausedstopped
- video stream stoppedfinished
- video stream finishederror
- when error is triggered while playing the video stream related with video streamprebuffering done
- in the launching of the video playback when pre-buffering of the video stream is done
Instantiation​
How to get updates of the Player Position
​
- Observe on the "playerPositionEvent" field from Diva Player
dpUtilsNode.observeField("playerPositionEvent", "onPlayerPosition")
- In observer get player position updates:
sub onPlayerPosition(evt as dynamic)
if evt.getData() <> invalid and evt.getData().position <> invalid
? evt.getData().position
end if
end sub
How to get updates of the Video Metadata
​
- Observe on the "videoMetadataEvent" field from Diva Player
dpUtilsNode.observeField("videoMetadataEvent", "onVideoMetadataChanged")
- In observer get video metadata updates:
sub onVideoMetadataChanged(evt as dynamic)
' From here integrator can know which video is being player, video id may be used to identify the current video being played. It is important because Diva can internally change the video being played, for instance thought video list or end of play.
' videoMetaData = evt.getData()
' ? videoMetaData
end sub
How to get updates of the Player State
​
- Observe on the "videoMetadataEvent" field from Diva Player
dpUtilsNode.observeField("playerStateEvent", "onPlayerState")
- In observer get video player state updates:
sub onPlayerState(evt as dynamic)
state = evt.getData()
divaPlayerStateConst = getDivaPlayerStateConst()
' start metadata polling when playback started
if state = divaPlayerStateConst["inited"]
'...
else if state = divaPlayerStateConst["playing"] or state = divaPlayerStateConst["paused"]
' Available states: "inited", "started", "buffering", "playing", "paused", "stopped", "finished", "error", "prebuffering done"
end if
end sub
function getDivaPlayerStateConst() as dynamic
if m.divaPlayerStateConst = invalid
m.divaPlayerStateConst = m.dpUtilsNode.callFunc("getPlayerStateConst")
end if
return m.divaPlayerStateConst
end function
Working sample code (.brs)​
sub init()
initScreen()
end sub
sub initScreen()
loadLibs()
end sub
sub loadLibs()
loadPlayer()
'Init of loading the BO Adapter lib
loadBOAdapter()
end sub
sub loadPlayer()
' Creates the ComponentLibrary (the DivaPlayerSDK in this case)
m.divaPlayerSDK = CreateObject("roSGNode", "ComponentLibrary")
m.divaPlayerSDK.id = "DivaPlayerSDK"
m.divaPlayerSDK.uri = "pkg:/resources/diva-roku-cl-sdk-5.7.0.zip"
' Adding the ComponentLibrary node to the scene will start the download of the library
m.top.appendChild(m.divaPlayerSDK)
m.divaPlayerSDK.observeField("loadStatus", "onDivaPlayerLoadStatusChanged")
end sub
sub loadBOAdapter()
' Creates the ComponentLibrary (the BO Adapter in this case)
m.divaBOAdapter = CreateObject("roSGNode", "ComponentLibrary")
m.divaBOAdapter.id = "DivaBOAdapter"
m.divaBOAdapter.uri = "pkg:/resources/diva-bo-adapter-cl-1.2.0.zip"
' Adding the ComponentLibrary node to the scene will start the download of the library
m.top.appendChild(m.divaBOAdapter)
m.divaBOAdapter.observeField("loadStatus", "onDivaPlayerLoadStatusChanged")
end sub
sub onDivaPlayerLoadStatusChanged()
if m.divaPlayerSDK.loadStatus = "ready"
if m.divaBOAdapter <> invalid and m.divaBOAdapter.loadStatus = "ready"
launchBOAdapter()
end if
end if
end sub
sub launchBOAdapter()
m.boAdapterNode = CreateObject("roSGNode", "DivaBOAdapter:DivaBOAdapter")
m.boAdapterNode.initData = {
"settingId": <video id>
"videoId": <video id>
"dictionaryId": "en_GB"
}
' Observe BO Adapter DiveLaunchParams
m.boAdapterNode.observeField("divaLaunchParams", "onBOAdapterDivaLaunchParamsHandler")
' Observe BO Adapter Dictionary
m.boAdapterNode.observeField("dictionary", "onBOAdapterDictionaryHandler")
' Observe BO Adapter VideoMetaDataNode
m.boAdapterNode.observeField("videoDataNode", "onBOAdapterVideoDataNodeHandler")
' Observe BO Adapter Entitlement Data
m.boAdapterNode.observeField("entitlementData", "onEntitlementDataHandler")
' Observe BO Adapter Settings
m.boAdapterNode.observeField("settingsNode", "onSettingsHandler")
' Observe BO Adapter when all necessary data for launching the Diva Player was loaded
' After getting this event you can launch the Diva Player
m.boAdapterNode.observeField("boAdapterReady", "onBOAdapterReady")
m.boAdapterNode.activateEntitlementPayloadMapCallback = true
m.boAdapterNode.observeField("entitlementPayloadMap", "onEntitlementPayloadMapHandler")
'Diva Player Utils Node
m.dpUtilsNode = getDivaPlayerUtilsNode()
' Observe Diva Player exit call
m.dpUtilsNode.observeField("divaPlayerExit", "onDivaPlayerExitHandler")
' Observe Diva Player actions
' Observe Diva Metadata update call
m.dpUtilsNode.observeField("metaDataUpdate", "onMetadataUpdateHandler")
' Get a request from the Diva Player on making the Entitlement request to the BE
m.dpUtilsNode.observeField("entitlementRequest", "onEntitlementHandler")
' Get event from the Diva Player for configuration Entitlement Service
m.dpUtilsNode.observeField("entitlementConfigurationRequest", "onEntitlementConfigurationHandler")
m.dpUtilsNode.observeField("playerPositionEvent", "onPlayerPosition")
m.dpUtilsNode.observeField("playerStateEvent", "onPlayerState")
m.dpUtilsNode.observeField("videoMetadataEvent", "onVideoMetadataChanged")
' Getting Diva Player Node
m.divaPlayer = m.dpUtilsNode.callFunc("getPlayer")
' Adding Diva Player for the visualisation
screensStack = m.getScreensStack()
screensStack.appendChild(m.divaPlayer)
m.divaPlayer.setFocus(true)
end sub
function getDivaPlayerUtilsNode() as dynamic
if NOT isValid(m.dpUtilsNode)
m.dpUtilsNode = CreateObject("roSGNode", "DivaPlayerSDK:DPUtilsNode")
end if
return m.dpUtilsNode
end function
sub onBOAdapterDivaLaunchParamsHandler(evt as dynamic)
data = evt.getData()
' Setup Diva Player launch parameters
m.dpUtilsNode.callFunc("setLaunchParams", data)
end sub
sub onBOAdapterDictionaryHandler(evt as dynamic)
data = evt.getData()
' Setup Diva Player dictionary
m.dpUtilsNode.callFunc("setDictionary", data)
end sub
sub onBOAdapterVideoDataNodeHandler(evt as dynamic)
data = evt.getData()
' Setup Diva Player Metadata
m.dpUtilsNode.callFunc("setMetaData", data)
end sub
sub onSettingsHandler(evt as dynamic)
data = evt.getData()
' Setup Diva Player Settings
m.dpUtilsNode.callFunc("setSettings", data)
end sub
sub onEntitlementDataHandler(evt as dynamic)
' Set to the Diva Player response from Entitlement Service
m.dpUtilsNode.callFunc("setEntitlementData", evt.getData())
end sub
sub onBOAdapterReady(evt as dynamic)
m.dpUtilsNode.callFunc("runPlayer")
end sub
sub onEntitlementPayloadMapHandler(evt as dynamic)
entitlementPayloadMap = evt.getData()
' Integrator can make changes in m.entitlementPayloadMap then send it back to the BO Adapter through "setEntitlementPayloadMap"
' Important: in case you activate Entitlement Payload Map Callback (activateEntitlementPayloadMapCallback = true)
' you need to observe on "entitlementPayloadMap" and then get data from this observer and send data back through the "setEntitlementPayloadMap" field in BO Adapter
' Without these actions, BO Adapted not make the Entitlement call. BO Adapter will wait for the Call Back from the Main Application
m.boAdapterNode.setEntitlementPayloadMap = entitlementPayloadMap
end sub
sub destroyBOAdapter()
if m.boAdapterNode <> invalid
m.boAdapterNode.unobserveField("error")
m.boAdapterNode.destroy = true
m.boAdapterNode = invalid
end if
end sub
sub onMetadataUpdateHandler(evt as dynamic)
data = evt.getData()
m.boAdapterNode.requestMetaDataUpdate = data
end sub
sub onPlayerPosition(evt as dynamic)
if evt.getData() <> invalid and evt.getData().position <> invalid
? evt.getData().position
end if
end sub
sub onPlayerState(evt as dynamic)
state = evt.getData()
divaPlayerStateConst = getDivaPlayerStateConst()
' start metadata polling when playback started
if state = divaPlayerStateConst["inited"]
'...
else if state = divaPlayerStateConst["playing"] or state = divaPlayerStateConst["paused"]
' Available states: "inited", "started", "buffering", "playing", "paused", "stopped", "finished", "error", "prebuffering done"
end if
end sub
sub onVideoMetadataChanged(evt as dynamic)
' From here integrator can know which video is being player, video id may be used to identify the current video being played. It is important because Diva can internally change the video being played, for instance thought video list or end of play.
' videoMetaData = evt.getData()
' ? videoMetaData
end sub
function getDivaPlayerStateConst() as dynamic
if m.divaPlayerStateConst = invalid
m.divaPlayerStateConst = m.dpUtilsNode.callFunc("getPlayerStateConst")
end if
return m.divaPlayerStateConst
end function
sub onEntitlementHandler(evt as dynamic)
data = evt.getData()
m.boAdapterNode.entitlementRequest = data
end sub
sub onEntitlementConfigurationHandler()
hbInterval = m.boAdapterNode.callFunc("getEntitlementHeartBeatInterval")
if hbInterval <> invalid and hbInterval > 0
m.dpUtilsNode.callFunc("setEntitlementConfiguration", {heartBeatInterval: hbInterval})
end if
end sub
sub onDivaPlayerExitHandler()
m.dpUtilsNode = invalid
'Destroy BO Adapter Node
destroyBOAdapter()
end sub