Skip to main content

Watch Together Android Mobile Plugin

Requirements​

  • minimum SDK version of the application to 23 or higher

Add WT SDK library to your project​

Package​

With a VXP GitHub account you can use package implementation by authorising your repository, i.e.

    def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties")))
maven {
url = uri("https://maven.pkg.github.com/deltatre-vxp/diva-android-releases")
credentials {
username = githubProperties['github.usr']
password = githubProperties['github.key']
}
}

// diva
implementation "com.deltatre.diva:divawatchtogetherplugin:1.0.4"

You will need to have a relevant Personal Access Token with package read permissions in order to utilise this approach.

Dependencies​

WT Library uses Android Data Binding and View Binding, so these libraries must be enabled in the gradle.

plugins {
...
id 'kotlin-kapt'
}
...
android{
...
buildFeatures {
dataBinding true
viewBinding true
}
...
}
dependencies {
...
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$livedata_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$viewmodel_version"
...
}

In order to use Diva Watch Together plugin, the WT-Sync and WT-Media Seenic's SDKs are needed.

allprojects {
repositories {
maven {
url "https://europe-west2-maven.pkg.dev/wt-service/wt-maven"

credentials {
username = "_json_key_base64"
password = "YOUR-SCEENIC-MAVEN-TOKEN"
}
authentication {
basic(BasicAuthentication)
}
}
}
}
dependencies {
...
// Watch Together SDK's
implementation 'com.wt:sdk:3.0.6'
implementation 'com.wtsync:sdk:1.6.0'
...
}

Usage​

Setup​

In this demo we are using DIVA player.

In order to use WT you need to implement the following Callbacks PlayerCallback

	interface PlayerCallback {
fun onPlayerStateChanged(state: State)
fun onPlayerPositionChanged(position: PlayerPosition)
fun onPlayerPlaybackRateChanged(rate: Float)
}

and WatchTogetherCallback

	interface WatchTogetherCallback {
fun playbackPositionChangeRequest(absolutePosition: Date?, relativePosition: Long?)
fun playbackStateChangeRequest(pause: Boolean)
fun playbackRateChangeRequest(rate: Float)
fun userCloseRequest()
}

Initialization​

First we have to create a DivaFragment, defining the PlayerCallback listener as the playerCallback parameter of DivaConfiguration :

	private var divaFragment: DivaFragment? = null
fun provideFullScreenDiva(): DivaFragment? {

val setting = DataProvider.getSettingHbsDemo(context = applicationContext) ?: return null
val dictionary = DataProvider.getDictionaryEnGB(context = applicationContext) ?: return null

val conf = DivaConfiguration(
this,
videoID,
...
null,
this //PlayerAPI Callback
)
// DIVA INSTANTIATION
divaFragment = DivaFragment.newInstance(conf)
return fullScreenDiva
}

We then need to initialize WT module by calling the init method with a FragmentActivity, the WT container ID, the Diva container ID, the id of the Activity's main ConstraintLayout and the URL of the WatchTogether API endpoint as parameters:

	WatchTogetherModule.init(
this,
R.id.watchTogetherContainer,
R.id.divaContainer,
R.id.divaActivity,
wtBackendEndpoint)

Before enabling the feature, set the WT button either using the default below as provided by the WatchTogetherModule, or by creating your own View:

	wtButton = WatchTogetherModule.providerDefaultButton()
wtButton?.setOnClickListener {
openWatchTogether()
}
divaFragment.features.watchTogether.setLauncherButton(wtButton)

Once the feature is enabled, we have to indicate to DIVA that the WT module is available by setting the status to Ready like this:

	divaFragment?.features.watchTogether.setReady()

When the user activates/uses the feature the status should be set to Active , and afterwards add the WatchTogetherCallback listener:

	divaFragment?.features.watchTogether.setActive()
WatchTogetherModule.addWatchTogetherListener(this)

In order for the WT module to work properly it requires some information about the player, such as position, playback rate and state. For this we need to user the PlayerAPI callback and pass the data to the WT module like this:

    override fun onPlayerPlaybackRateChanged(rate: Float) {
WatchTogetherModule.playerRateUpdated(rate)
}

override fun onPlayerPositionChanged(position: PlayerPosition) {
WatchTogetherModule.playerPositionUpdated(position.absolutePosition, position.relativePosition)
}

override fun onPlayerStateChanged(state: State) {
//TODO: Handle different states
WatchTogetherModule.playerStateUpdated(state.ordinal)
}

Then the WT module will send back instructions to pass to the player though the PlayerAPI in order to sync the video for all users:

  override fun playbackPositionChangeRequest(absolutePosition: Date?, relativePosition: Long?) {
if(absolutePosition != null){
divaFragment?.features?.playerApi?.sendPlayerCommand(PlayerCommands.seekAbsolute(absolutePosition))
} else if (relativePosition != null) {
divaFragment?.features?.playerApi?.sendPlayerCommand(PlayerCommands.seek(relativePosition))
}
}

override fun playbackStateChangeRequest(pause: Boolean) {
if(pause){
divaFragment?.features?.playerApi?.sendPlayerCommand(PlayerCommands.pause)
}else {
divaFragment?.features?.playerApi?.sendPlayerCommand(PlayerCommands.play)
}
}

override fun playbackRateChangeRequest(rate: Float) {
divaFragment?.features?.playerApi?.sendPlayerCommand(PlayerCommands.playbackRate(rate))
}

In order to change the video title in portrait mode, you should use the setVideoTitle method, like this:

	WatchTogetherModule.setVideoTitle("VideoTitle")

To allow users to be identified during a call the name (username or whatevre) must be provided. To do so right after the initialisation of the Watch Together module, you must call setUserName method that takes in input as paramenter a String and optionally a function (String) -> String if you want to define how to generate the user's initals instead of using the default logic:

	val username = "foo"
val initialsFx: (String) -> String = {
generateInitials(it)
}
WatchTogetherModule.setUserName(username, initialsFx)

In order to correctly manage the UI according to the device's orientation, when a configuration change happen the method setupUI(configuration) must be called:

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
WatchTogetherModule.setupUI(newConfig)
}

When the user close the feature the status should be set to Ready , and call the method close:

	divaFragment?.features.watchTogether.setReady()
WatchTogetherModule.close()