Using the OtvAa Wrapper API
The wrapper-app and bmwrapper-app source code demonstrate the basic functionality described below. Their design are 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 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 application communicates with OtvAnalyticsAgentWrapper
which in turn:
instantiates, configures and communicates with an
OtvAnalyticsAgent
instanceconfigures the legacy Insight Agent (if required)
attaches listeners to the provided Player (Connect Player/Bitmovin 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 application 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": {
"collectorURL":"https://url-to-insight-collector",
"reportingInterval": 30, // seconds (default 60)
"samplingInterval": 15, // 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 player object created by the application.
Set Connect player object:
OTVVideoView mVideoView;
......
OtvAaError result = wrapper.setPlayer(mVideoView, OtvAnalyticsAgentWrapper.PLAYER_TYPE_CONNECT);
Set Bitmovin player object:
Player mBitmovinPlayer;
......
OtvAaError result = wrapper.setPlayer(mBitmovinPlayer, OtvAnalyticsAgentWrapper.PLAYER_TYPE_BITMOVIN);
If the player is set (changed) during a playback session, then no further actions will be detected for that playback session.
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 setting stream URL 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 https://docs.nagra.com/otv-analytics-agent/latest/otv-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
Synchronous errors are the OtvAaError
return values from method calls to the wrapper.
Other asynchronous 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 OpenTV Analytics Agent for Android APIs .