Appearance
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
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
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
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.
Google ads
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)