Skip to content

Ease Live Bridge Android SDK

This is a guide for customers/developers to get up and running with the Ease Live Bridge SDK for Android.

Customers that have a native app and want to integrate it with Ease Live need a convenient way to do so. They may have their own player or a specific player they want to use. Players generally have a custom way of reading timecodes from their streams. With the Ease Live Bridge SDK the customer can do this the easiest and fastest way possible.

Requirements

  • Android 5 (API 21) or newer.
  • Android Studio 3.0 or newer.

SDK Architecture

UML Component Diagram

The main components in the SDK are:

  • EaseLive bridge SDK: responsible for
    • loading the EaseLive url into a proper View
    • create the communication layer between the Player and the EL web app
    • handle EL SDK lifecycle
  • Player: responsible for the playback and for reading the metadata that the stream includes.
  • PlayerPlugin: responsible for the communication between the EL SDK and the player.

Example project

Download example project

In Android Studio select File → New → Import Project, then select the directory where you extracted the example project.

Get started

Gradle repository

Add the dependency to your build.gradle:

repositories {
    maven {
        url "https://sdk.easelive.tv/maven"
    }
}

dependencies {
    implementation 'tv.easelive:easelivesdk:2.11.0'
}

The EaseLive instance

Every Ease Live Bridge application starts by creating a new EaseLive instance with one of the constructor functions. The initialization of the EaseLive bridge will start when the create() method is called on the EaseLive object.

kotlin
import tv.easelive.easelivesdk.EaseLive;

// project and environment to load
val accountId = "tutorials"
val projectId = "0346ae3e-7a91-4760-bcd3-cd84bb6790dd"
val programId = "2d2711ff-6ff2-41c1-a141-060e9ffa2c38"
val env = "prod"
val streamId = "main" // Optional Stream ID used for timecode settings. Defaults to "main"

easeLive = EaseLive(this,
            parentView,
            accountId,
            projectId,
            programId,
            env,
            hashMapOf("customValue" to 1), // optional query parameters added to the URL loaded from the environment
			streamId,
            playerPlugin)

easeLive.create()

The values in the code above will load in an SDK installation UI that will help to verify your implementation.

By default the available environments are: "prod", "staging" and "dev". Environments can be configured in project settings.

The playerPlugin is any class that wraps the player functionality and implements the PlayerPluginInterface that allows the SDK to communicate with the player.

See PlayerPlugin for implementation of a plugin for a custom player.

Apps targeting minSdkVersion 20 or lower

Skip this step if your app targets minSdkVersion 21 or newer. If your app still targets minSdkVersion 20 or lower, it is necessary to conditionally use EaseLive only when running on a supported Android version.

Force the SDK to be included in AndroidManifest.xml:

xml
<uses-sdk tools:overrideLibrary="tv.easelive.easelivesdk" />

Conditionally use EaseLive when minimum requirement is available:

kotlin
if (Build.VERSION.SDK_INT < tv.easelive.easelivesdk.BuildConfig.MIN_SDK_VERSION) {
    // Android version too old
} else {
    // load with EaseLive on supported Android version
    easeLive = EaseLive(this, easeLiveView, ...)
    easeLive.create()
}

Lifecycle diagram

Alt text

Create

The method easeLive.create() should be called when the EL SDK need to be created and to initialise any object needed by the plugins.

Create should usually be called when the activity triggers the Android lifecycle method Activity#onCreate().

Load

The method easeLive.load() should be called on the EL SDK object when the app need to start executing its internal behaviour. For example a PlayerPlugin should call load to start loading the url where the video stream is located.

Load should usually be called when the activity triggers the Android lifecycle method Activity#onResume().

Pause

The method easeLive.pause() should be called on the EL SDK object when the app goes in foreground, so when it's not visible but not in focus anymore.

Pause should usually be called when the activity triggers the Android lifecycle method Activity#onStop().

Destroy

The method easeLive.destroy() should be called when the app goes in background or the app is destroyed. This method takes care of calling the destroy method on each of the plugins, and this method takes care of removing the objects and listeners safely.

Destroy should usually be called when the activity triggers the Android lifecycle method Activity#onDestroy().

Change program

The method EaseLive#setProgram(projectId, programId, env, params) can be called when the app wants to change the loaded program in the current EaseLive instance. The typical case to use this is when the app loads a new video stream in the current video player or a different program starts in the current stream.

Change stream

If the video stream changes during a program, stream ID can be changed using EaseLive#setStreamId(streamId) to apply timecode settings for the stream.

Error handling

Errors from the SDK are broadcast with the broadcast action EaseLiveNotificationKeys.EASE_LIVE_ERROR. The error object can be retrieved from the extra EaseLiveNotificationKeys.EXTRA_ERROR in the broadcast intent . The error object contains information about the error level (fatal or warning) and a string value with the verbose reason for the error.

When the SDK experiences a fatal error, the SDK should be removed from the app calling easeLive.destroy() that takes care of removing EaseLive correctly from memory.

kotlin

easeLiveBroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            EaseLiveNotificationKeys.EASE_LIVE_READY -> {
                // the overlay UI loaded successfully
            }
            EaseLiveNotificationKeys.EASE_LIVE_ERROR -> {
                intent.getParcelableExtra<Error>(EaseLiveNotificationKeys.EXTRA_ERROR)?.let { error ->
                    if (error.level == Error.LEVEL_FATAL) {
                        // fatal error. For example the UI failed to load.
                        // remove the overlay and fallback to a normal video
                        easeLive?.destroy()
                    } else {
                        // non-fatal error/warning.
                    }
                }
            }
        }
    }
}
LocalBroadcastManager.getInstance(this)
    .registerReceiver(easeLiveBroadcastReceiver, EaseLive.getIntentFilter())

Components

The SDK contains a few default components and plugins needed to have a fully working EaseLive instance. To allow the communication between those components, events are sent as broadcasts. Any additional plugins can communicate with the default components using those events.

Event dispatcher

See Events for a list of events that are emitted by the SDK and plugins.

EaseLive SDK

The EaseLive instance is responsible of calling lifecycle methods and to send the messages related to any error sent to the SDK so that the player and the app can update accordingly. Furthermore the SDK sends some messages from the UI overlay web app to the app so that the player knows when the web app want it to change state or other settings.

Player plugin

The player plugin handles the communication between the player and the EaseLive SDK. See PlayerPlugin for implementation details.

View plugin

The view plugin is used to display the overlay UI. The default implementation uses a webview to display the UI.

Bridge plugin

The bridge plugin is used to send events between the plugins and the overlay UI.

Custom plugins

Plugins can add additional functionality to the EaseLive instance. There is no strictly defined scope for a plugin, however it is usually used for adding extra functionality to the bridge by adding listeners to the lifecycle events. This is achieved by creating a class implementing the ComponentInterface and registering it using easeLive.use(plugin) before calling easeLive.create().

Custom bridge messages

Custom messages can be used to send data from the app to the Ease Live overlay, and to receive data from the overlay. This can be used for custom functionality in the overlay.

Sending a message to the overlay

kotlin
val jsonObject = JSONObject()
jsonObject.put("event", "myPrefix.myEvent")
val metadata = JSONObject()
metadata.put("myCustomValue", "some data")
jsonObject.put("metadata", metadata)

val broadcast = Intent(EaseLiveNotificationKeys.APP_MESSAGE)
broadcast.putExtra(EaseLiveNotificationKeys.EXTRA_JSON_STRING, jsonObject.toString())
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast)

To receive this message in the overlay configure a "Bridge message is received" trigger on the Bridge data source in the Studio project.

Receiving a message from the overlay

A message can be sent from the overlay by configuring a "Send bridge message" trigger in the Studio project.

Such messages can be received in the app by listening for it:

kotlin
val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (EaseLiveNotificationKeys.BRIDGE_MESSAGE == intent.action) {
            val jsonString =
                intent.getStringExtra(EaseLiveNotificationKeys.EXTRA_JSON_STRING)
            try {
                val jsonObject = JSONObject(jsonString)
                if ("myPrefix.myEvent" == jsonObject.getString("event")) {
                    val metadata = jsonObject.getJSONObject("metadata")
                    val value = metadata?.getString("myCustomValue")
                }
            } catch (e: JSONException) {
            }
        }
    }
}

val filter = EaseLive.getIntentFilter()
filter.addAction(EaseLiveNotificationKeys.BRIDGE_MESSAGE)
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter)

Android TV

When used on Android TV the app should implement handling of moving focus to and from the overlay, and sending key events to the overlay while it has focus.

An example using Leanback controls with ExoPlayer can be found in the TvMainActivity class in the example project.

Calling easeLive.requestFocus(), will move focus from the native app to the overlay. This can be set up to trigger from a key event while the player controls are hidden, or from an action in the player controls. See an example of the action in ProgressTransportControlGlue or the key event in TvMainFragment.dispatchKeyEvent

After giving focus to the overlay easeLive.hasFocus() will be true if the overlay took focus. As long as this is true, a key press in the app should call easeLive.dispatchKeyEvent() to forward the key event to the overlay.

When the user presses the Back-button at the root of the overlay, it will trigger the event to show the player controls. At this point the app should take focus, so that key events can be used to navigate the native player controls. This is done by calling requestFocus on the player control view. See the TvMainActivity.showControlsOverlay() in the example project.

Follow instructions on WebView API for Ads to add Google Mobile Ads SDK to your app.

Instead of the steps for adding and registering a new WebView, register the WebView that is created by EaseLive:

kotlin
// listen for EaseLive creating a webview
val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (EaseLiveNotificationKeys.VIEW_CREATED == intent.action) {
			// EaseLive has created a webview. Register it with the Google ads instance
			(easeLive?.viewPlugin?.view as? ExtendedWebView)?.let { webView ->
				MobileAds.registerWebView(webView)
			}
        }
    }
}

val filter = EaseLive.getIntentFilter()
filter.addAction(EaseLiveNotificationKeys.VIEW_CREATED)
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter)