Android - Java/Kotlin

Overview

Follow this step-by-step tutorial to implement the video playback Synchronization SDK.

While the client-side SDK will take care of most of the functionality, in order to make this sample application work, you will need to use the API_KEY provided to you.

Full code samples can be found here

Requirements

To complete this guide successfully the following prerequisites are required:

Authentication

An Access Token is needed in order to allow a client to connect to a sync group.

Note: It is important that the client application does not request an Access Token directly from the backend. By doing that you risk exposing the API_TOKEN and API_SECRET.

Acquiring an Access Token

curl -iL --request GET --url https://YOUR_CAS_URL/sync/token --header 'auth-api-key: API_KEY'   --header 'auth-api-secret: API_SECRET'

The Access Token is a JWT token - more about jwt you can read - here.

A successful response will look like that:

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...."
}

You can get your API_KEY and API_SECRET in your private area, here.

Note: Every Sync Token corresponds to one specific sync group only. To allow two different clients to connect to the same group, the clients need to use the same Access Token.

Create a project

  • Open the Android Studio and select New Project from the File menu

  • Select Empty Activity and click next

  • Choose Java or Kotlin as your programming language for the project

  • Configure your project's location, application, and package names

  • Set the minimum SDK version of the application to 21 or higher

Add the sync SDK library to your project

  • Create (if it does not exist) in the project a libs directory under the app folder

  • Add the file wtsyncsdk_v....aar to the libs folder

  • Edit the application's build.gradle file (in the app folder) with SDK

android {
    // Required
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    
    // Required
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/ASL2.0'
        exclude("META-INF/*.kotlin_module")
    }
}
dependencies {	
    implementation files('libs/wtsyncsdk_v....aar')	
    implementation 'androidx.core:core-ktx:1.7.0'
}

Permissions

  • Add the following permissions to the AndroidManifest.xml file under the app/src/main folder in the project above the application tag.

<uses-permission android:name = "android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name = "android.permission.INTERNET" />

Instantiating the SDK

  • SDK builder - Call SyncSdkBuilder to instantiate the SDK.

mSyncSdk = new SyncSdk.SyncSdkBuilder()
      .accessToken(mAccessToken)      // mAccessToken - authorization token
      .name(mDisplayName)             // mDisplayName - username
      .syncListener(this)             // this - SyncListener object
      .build();

  • Start synchronization

if (mSyncSdk != null) {
    mSyncSdk.startSync();
}

  • Stop synchronization

if (mSyncSdk != null) {
    mSyncSdk.stopSync();
}

  • Group play video

if (mSyncSdk != null) {
    mSyncSdk.groupPlay();
}

  • Group pause video

if (mSyncSdk != null) {
    mSyncSdk.groupPause();
}

  • Group seek video

if (mSyncSdk != null) {
    mSyncSdk.groupSeek(position);
}

  • Group seek success

if (mSyncSdk != null) {
    mSyncSdk.groupSeekSuccess(position);
}

Managing synchronization logic

The synchronization logic is managed using callbacks, using them you will be able to create the interaction you need.

  • In the sample application, you can see an example for implementing the necessary callbacks

public class MainActivity extends AppCompatActivity implements SyncListener {
    ...

    @Override
    public void onClientList(@NotNull List<SyncClient> syncClients) {
        // remote sync client joined to the group, update ui using adapter
        // update ui with the list of connected clients in the same group
    }
    
    @Override
    public void onSetPlaybackRate(float rate) {
        // setting playback rate
    }

    @Override
    public void onPlaybackFromPosition(long position) {
       // playback from position
       // player.seekTo(position);
    }

    @Override
    public long onGetPlayerPosition() {
        // getting player position
        // Implement your logic to extract player position in miliseconds,
        // be sure that all clients connected to the same group extracts relevant
        // and from the same content timestamps(position)
        // return player.getCurrentPosition();
        return 0L;
    }

    @Override
    public float onGetPlaybackRate() {
        // getting playback rate
        // Implement your logic to extract player rate/speed
        // return player.speed;
        return 0f;
    }

    @Override
    public void onSyncInfo(@NotNull SyncInfo syncInfo) {
        // information about synchronization's accuracy and delta
        // syncInfo.accuracy 0.0% - 100.0%
        // syncInfo.delta starts from 0L and describes how big is delay
        // in miliseconds, can be negative value     
    }
    
    @Override
    public void onSyncGroupPlay() {
        // received an event onSyncGroupPlay()
        // play function should be called if its not playing already
        if (!player.isPlaying()) { 
            player.play();
        }   
    }
    
    @Override
    public void onSyncGroupPause() {
        // received an event onSyncGroupPause()
        // pause function should be called if its still playing
        if (player.isPlaying()) { 
            player.pause();
        }   
    }
    
    @Override
    public void onSyncGroupSeek(long position) {
        // received an event onSyncGroupSeek(long position) with position parameter
        // seek function should be called to the given position
        // works with VOD
        if (!player.isCurrentWindowLive()) { 
            player.seekTo(position);
        }
        // Client should send success seek request every time onSyncGroupSeek called
        if (mSyncSdk != null) {
            mSyncSdk.groupSeekSuccess(position);
        }
    }

    @Override
    public void onSyncDisconnected() {
        // client has been disconnected from the group. All connections 
        // will be closed. Clear ui and data
    }
}

Running the application

Once coding is finished, you should be able to run the application in the Android Studio emulator.

You can view the complete Watch Together sample application here

Support

Need technical support? contact us at Support@sceenic.co.

Last updated