To test this feature and view the example code, please see the Android SDK 5 Example Code Quick Start guide.

Using the Insight Agent wrapper class, the application can report player metrics to the Insight servers. The wrapper class uses the Agent to manage Insight sessions alongside playback, during which content and playback monitoring information are collated and uploaded to the Insight servers. A session lifecycle equates to the playback of one content, starting when the content is loaded into the player and ending when the content is unloaded.

The application is responsible for:

  • Instantiating and driving the player
  • Providing metadata about the content

The Agent wrapper is responsible for:

  • Observing metrics and events on the player
  • Reporting metrics and events to the Insight servers

Prerequisites

An additional library in the insight-agent-<version>.aar package performs the reporting mechanism to Insight servers. There is no need to modify your build.gradle file as the player SDK includes all the dependency declarations. You will need to copy the Insight library file to the common/libs directory of the example code project (or wherever your application defines it as the library directory).

The Agent library is provided with the player SDK library for your convenience. This additional library can be obtained through the Insight Customer Service Desk. However, the Agent wrapper in the SDK is designed to work with the version provided in the SDK package.

Example code

For Insight to be available, the Agent wrapper class must be configured during instantiation. This can be done explicitly by providing a configuration structure or implicitly using a configuration file. As the configuration is usually persistent for the operator, NAGRA recommends using a configuration file.

Configuration using a configuration structure (programmatic configuration)

For dynamic/programmatic configuration, you must first instantiate an com.nagra.insight.agent.InsightConfig configuration class with your parameters specific to your account and application (see InsightConfig description in the API documentation), and then use the explicit configuration constructor:

Agent(Context xContext, InsightConfig config)
InsightConfig is a class defined in the Agent library to configure all parameters reported to the Insight server. For details of this class, see the Insight documentation in the Insight Customer Service Desk.

or
Agent(Context xContext, InsightConfig config, AgentConfig agentConfig)
AgentConfig is a class used to configure the Agent wrapper. It can set the Agent to automatically report changes in video quality rather than using playback metrics retrieved from your player.

Configuration using a configuration file

NAGRA uses a configuration file for default/implicit configuration, which must be present at src/res/raw/analytics.json of the integrating application. The Insight Agent reads the configuration file when the application creates the Agent using the constructor:

Agent(Context xContext)
or
Agent(Context xContext, String deviceId)

The deviceId parameter has to be unique and persistent for the device. If it is omitted, the Agent wrapper will attempt to use the one provided by the Android system ( Settings.Secure.ANDROID_ID). In some environments, this value is not unique to one device, and you will have to provide one. An example configuration file is shown below.

"insightCollectorURL" : "https://collector.insight-stats.com/api/v1/",
  "samplingInterval" : "10",
  "reportingPeriod" : "30",
  "appName":"OpenTV Player Sample App",
  "appVersion":"5.x",
  "deviceType":"handheld",
  "operatorId":"9c703ed0309f"
GROOVY

When using this as a reference, update fields specific to your account and application.

Import classes

To use the Insight Agent, place the Insight Analytics Agent library and the SDK under common\libs; the integrating application then needs to import the classes.

import nagra.insight.agent.Agent;
import nagra.insight.agent.utils.ContentInfoHolder;
JAVA

Request READ_PHONE_STATE permission (API 29 and above)

Before setting up Insight, runtime permission requests for READ_PHONE_STATE are necessary when both of the following conditions are true:

  • The application will run on Android Q devices
  • The application's targetSdkVersion is 29 (Android Q) or higher

The following code will, if necessary, show a system dialogue box requesting approval from the user. If permission has not already been granted, the user's approval comes back asynchronously in the onRequestPermissionsResult() callback, which is an Activity override.

if (checkReadPhoneStatePermission()) {
  // Permission granted. Can continue.
} else {
  // Permission not granted yet. Need to wait for user's approval.
}

public boolean checkReadPhoneStatePermission() {
  boolean hasPermission = (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED);
  if (!hasPermission) {
    requestReadPhoneStatePermission();
  }
  return hasPermission;
}

@TargetApi(23)
public void requestReadPhoneStatePermission() {
  if (shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) {
	// Show our own request permission dialog before popping the system one.
	AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
	dialogBuilder.setTitle("External permission required for Read Phone State");
	dialogBuilder.setPositiveButton("Ok", (dialog, which) ->
	  requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1))
	  .show();
  } else {
	// Show system dialog to request permission
	requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
  }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  // Dialogue results callback
  if (requestCode != 1) {
	// Not coming from our request, tagged as 1
	return;
  }
  if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
	// Permission refused/not granted by user
  } else {
	// Permission granted by user
  }
}
JAVA

Create Agent

Once the package has been imported, the application can create the Agent in the correct place:

mInsightAgent = new Agent(mContext);
JAVA

As the same Agent can be reused for multiple playback sessions, there is usually no need to instantiate this class more than once.

Session control

The Agent is only responsible for collating the analytics data; it needs the application to control an Insight session alongside playback. The application should start the session to align with the stream's playback.

  • For both live and VOD, a session should start when playback commences.
  • For VOD streams, a session should stop when the playback finishes, whether by error, user action or playout.
  • For live streams, a session should end when the stream is switched or is stopped by an error.

Preparing content information

When starting the session, the application should prepare the content information that the session will need; this includes metadata related to the current stream. If the application has all metadata available before a stream is selected, this can be created on stream selection. If not, some can be obtained from the video view once it is prepared, in which case something similar to the following snippet would need to be called after receiving the OnPreparedListener.onPrepared event.

    // Set stream metadata
    ContentInfoHolder contentInfoHolder = new ContentInfoHolder();
    contentInfoHolder.setDuration(mOTVVideoView.getDuration());
    contentInfoHolder.setContentId("ContentId");
    contentInfoHolder.setContentName("ContentName");
    contentInfoHolder.setAudioLanguage("AudioLang"); // May be changed over the course of a session
    contentInfoHolder.setSubtitleLanguage("SubsLang"); // May be changed over the course of a session
    contentInfoHolder.setChannelId("ChannelId");
    contentInfoHolder.setEventId("EventId");
    contentInfoHolder.setEventName("EventName");
    contentInfoHolder.setType((mOTVVideoView.getDuration() == -1) ? "LIVE" : "VOD");
    List<String> genres = new ArrayList<>();
    genres.add("Drama");
    genres.add("Thriller");
    contentInfoHolder.setGenreList(genres);
JAVA

Preparing user information

When starting the session, the application should prepare the user information which the session will need; this includes metadata related to the user account.

    // Set user metadata
    UserInfoHolder userInfoHolder = new UserInfoHolder();
    userInfoHolder.setUserId("UserId");
    userInfoHolder.setAccountId("AccountId");
    userInfoHolder.setGender("Gender");
    userInfoHolder.setAge(21);
    userInfoHolder.setAgeRange("AgeRange");
    userInfoHolder.setCategory("Category");
    userInfoHolder.setFullName("FullName");
    userInfoHolder.setStreet("Street");
    userInfoHolder.setCity("City");
    userInfoHolder.setState("State");
    userInfoHolder.setPostcode("Postcode");
    userInfoHolder.setCountry("Country");
    userInfoHolder.setCorp("Corp");
    userInfoHolder.setNode("Node");
JAVA

Starting the session

After getting all the content information available, the application can start the session with the content information and the OTVVideoView. Beware of the timing of starting the session; the application should only start the session after the onPrepared event has been received.

mInsightAgent.startSession(mNmpVideoView, contentInfoHolder, userInfoHolder);
JAVA