Using the OtvAa Wrapper API
The wrapper-app source code demonstrates the basic functionality described below. Its design is very similar to the agent-app as described in Using the OtvAa Agent API.
An addition to the wrapper app UI comparing to the agent app is the inclusion of a thumbnail-sized Connect Player view and some basic playback buttons in the Submit Activity tab. There is no significance to the player content so it is made very small to reserve screen area for other controls.
The wrapper-app communicates with OtvAnalyticsAgentWrapper which in turn:
instantiates, configures and communicates with an
OtvAnalyticsAgentinstanceconfigures the legacy Insight Agent (if required)
attaches listeners to the provided OpenTV Connect Player, extracts events and metrics and reports them to the Analytics Server (via
OtvAnalyticsAgent).
As the use of OtvAnalyticsAgent and OtvAnalyticsAgentWrapper are mutually exclusive by a single app, the wrapper-app only handles OtvAnalyticsAgentWrapper. However, the API is very similar, and any submitActivity() call on OtvAnalyticsAgentWrapper is consequently passed on to the OtvAnalyticsAgent instance.
Initialising the wrapper
Similar to OtvAnalyticsAgent, the setting up of the OtvAnalyticsAgentWrapper is done in two steps. First, we instantiate the agent with the application context:
OtvAnalyticsAgentWrapper wrapper = new OtvAnalyticsAgentWrapper(getApplicationContext());
The second step is initialising the newly-created instance. The OtvAnalyticsAgentWrapper.initialise() takes three parameters, and returns an OtvAaError value, which, if successful, returns the OK value.
The first parameter of the initialisation is the wrapper and Insight configuration as a JSON object. If the Insight agent is not required, the only value required is samplePeriod. If Insight is required, then the Insight configuration parameters are added all in an insightConfig section:
{
"samplePeriod":30,
"insightConfig": {
"insightCollectorURL":"https://url-to-insight-collector",
"reportingInterval": 1, // minutes (1-60, default 30)
"samplingInterval": 20, // seconds (15-reportingInterval, default 30)
"appName":"OtvAa Wrapper Sample App",
"appVersion":"5.x",
"deviceType":"handheld",
"deviceId": "my-device-id"
"operatorId":"my-op-id"}
}
}
The other two parameters in the initialisation method are similar to the two parameters in agent-app: configuration for the agent and an instance of an OtvAaReportListener implementation. See Initialising the agent in the previous page.
With the above three parameters we can now initialise the wrapper (and the downstream agent):
OtvAaError result = wrapper.initialise(wrapperConfigJson,agentConfigJson,reportListener);
Note that you can check if initialisation is successful in two ways: either by checking that
result == OtvAaError.OK
or by checking
boolean success == Agent.isInitialised()
Updating the Configuration
The configuration of the wrapper and agent may need to be changed. With the same caveats described in Updating the Configuration in the previous page, you can update configuration as follows:
OtvAaError result = wrapper.updateConfig(wrapperConfigJson, agentConfigJson);
Setting the Player
Set the player so that the wrapper can automatically detect some activities from the player, and automatically populate some of the metadata for other activities. The player should be set before the playbackStart() function is called so that the initial playback events are already reported.
The player parameter is a reference to the OTVVideoView object created by the application.
OtvAaError result = wrapper.setConnectPlayer(myPlayer);
If the player is set (changed) during a playback session, then no further actions will be detected for that playback session.
A player may be removed by calling:
wrapper.setConnectPlayer(null);
Starting a Playback Session
playbackStart() must be called by the client application to provide stream information which is not available from the player. If possible, the playback session should be started immediately before calling the myPlayer.setVideoPath(selectedStream) function on the player to request playback. If this is not possible then it should be started as soon as possible after the playback is requested on the player.
The parameters of playbackStart() are:
metadata
insightContent
insightUserInfo
If insight is not enabled, then the two insight parameters may be omitted.
If insight is enabled, insightUserInfo may be omitted if insight is required to run in anonymous mode.
playbackStart Metadata:
{
// The following are important as they're used to
// identify the playback session in subsequent activities
"playbackSessionId": "<UUID/GUID>",
"editorialID:"" "editorialChannelId",
"contentSource": "<IPTV/OTT/Blend>",
"ContentType": "live-event",
"railId": "...",
"Depth": "...",
"hdepth": "...",
"vdepth": "...",
"templateId": "...",
"technicalId": "...",
"programmeId": "...",
"seriesId": "...",
"deepLinkId2: "..."
}
Insight Content Info
ContentInfoHolder contentInfoHolder = new ContentInfoHolder();
// Set stream metadata for Insight
contentInfoHolder.setDuration(player.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.setUri(uri);
contentInfoHolder.setType("VOD"); // Available options : VOD and LIVE
if (isLive) {
contentInfoHolder.setChannelId("123456");
contentInfoHolder.setChannelName("BBC1");
contentInfoHolder.setEventId("abcdef"); // optional
contentInfoHolder.setEventName("live tv"); // optional
contentInfoHolder.setType("LIVE")
}
List<String> genres = new ArrayList<>();
genres.add("Drama");
genres.add("Thriller");
contentInfoHolder.setGenreList(genres);
Insight User Info
UserInfoHolder userInfoHolder = new UserInfoHolder();
userInfoHolder.setUserId("User001");
userInfoHolder.setAccountId("account001");
userInfoHolder.setGender("male");
userInfoHolder.setAge(37);
userInfoHolder.setAgeRange("AlwaysTheSame");
userInfoHolder.setCategory("D'oh");
userInfoHolder.setFullName("Homer J Simpson");
userInfoHolder.setStreet("Evergreen Terrace");
userInfoHolder.setCity("Springfield");
userInfoHolder.setState("Idono");
userInfoHolder.setPostcode("1DK");
userInfoHolder.setCountry("US");
userInfoHolder.setCorp("Corp");
userInfoHolder.setNode("Node")
playbackStart()
OtvAaError result = wrapper.playbackStart(metadata, insightContent, insightUserInfo);
Submitting Non-Playback Actions
Non-playback actions will not be automatically detected by the wrapper, so must be submitted by the client application, for example:
// adDeliveredMetadata:
// {
// // No need for appSessionId as it is auto populated
// // No need for playbackSessionId as it is auto populated
// "adID": "my-ad-id",
// "trackingAssetId": "my-tracking-asset-id",
// "adSupplier": "my-ad-supplier"
// }
OtvAaError result = wrapper.submitActivity(OtvActivity.AdDelivered, adDeliveredMetadata);
see OpenTV Analytics Activities to find which activities are automatically generated by the wrapper as well as which metadata is automatically populated.
Stop Playing and Clean-up
A playbackStop activity is optional, but recommended if possible, when stopping one playback and starting another. The next playbackStart activity will be used to find when the previous session stopped.
Sometimes it is not possible to guarantee clean up at the end of a playback or application session (e.g., if the user navigates away from the application or the application is sent to the background), however the client application should endeavour to clean up using the following sequence to ensure no loss of data:
JSONObject stopMetadata = // Create a metadata object with at least the Position field
OtvAaError result = wrapper.submitActivity(OtvActivity.PlaybackStop, stopMetadata);
:
result = wrapper.submitActivity(OtvActivity.AppEnd);
:
wrapper = null;
Error Handling
Synchronour errors are the OtvAaError return values from method calls to the wrapper.
Other ansynchronous errors, mostly the results of network operations and calls to the server, would be sent to the OtvAnalyticsAgent.tvAaReportListener.onError(OtvAaError xErrorCode, int xExtra) callback, either from the OtvAnalyticsAgenttWrapper instance or the OtvAnalyticsAgent instance it controls.
See the API documentation at OTV Analytics Agent for Android APIs .