Difference between revisions of "DCR Denmark Video Android SDK"

From Engineering Client Portal

(Sequence of Calls)
(Step 7 : Disclose Nielsen Privacy Statement)
(29 intermediate revisions by 3 users not shown)
Line 22: Line 22:
 
|}
 
|}
  
__TOC__
+
== Step 1: Setting up your Android Development Environment  ==
== Implementation ==
+
<br />
This guide covers implementation steps for Android Studio utilizing the Standard Nielsen SDK for DCR.
+
1) Ensure to unzip the Nielsen App SDK zip file and copy the "AppSdk.jar" into the app/libs folder on the App’s project. Add it as dependency.<br />
{| class="wikitable" style="background-color:#c6f5c5;"
+
2) Add the following permissions on the project’s "AndroidManifest.xml" file.<br />
|-
 
| If you are building an app for the 'kids category' please review the [https://engineeringportal.nielsen.com//docs/DCR_Video_Android_SDK#Special_Note_Regarding_Apps_in_the_Kids_Category Opt Out Requirement].
 
|}
 
=== How to obtain the NielsenAppApi ===
 
The Nielsen AppSDK can either be downloaded directly or can be integrated directly within an application through the use of Gradle. We recommend using the Gradle-based integration whenever possible to ensure you maintain the most recent changes and enhancements to the Nielsen libraries.
 
* [[Digital_Measurement_Android_Artifactory_Guide|Select to obtain Gradle implementation guide]]
 
* [[Special:Downloads|Select to Download Directly]]
 
 
 
== Setting up your Development Environment  ==
 
 
 
=== Configuring Android Development Environment ===
 
*The Nielsen App SDK (located in the [https://engineeringportal.nielsen.com/docs/Special:Downloads Downloads section] of the website) class is the primary application interface to the Nielsen App SDK on Android.
 
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.
 
 
 
'''Nielsen App SDK is compatible with Android OS versions 2.3+. Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.'''
 
 
 
The requirement for the Java ''AppSdk.jar'' library and the ''libAppSdk.so'' native library will depend on the type of host application that will make use of them.
 
* '''For Video player applications'''
 
** The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 3.0 and later will support it natively).
 
** If the player application uses a 3rd party media player implementing its own HLS, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.
 
 
 
Once SDK is downloaded ensure to unzip the Nielsen SDK and copy the AppSdk.jar in your app (Android Studio) libs folder, then right click the AppSdk.jar and select '''Add As Library'''.
 
Ensure the AppSdk.jar file is added in 'build.grade (App Level) file.
 
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture.
 
 
 
==== Google Play Services ====
 
Add the Google Play Services in the project,
 
Steps: Android Studio -> File -> Project Structure ->(In module selection) select App -> Dependencies (tab) -> Click "+" button and select <code>"com.google.android.gms:play-services"</code>.
 
Ensure it is added in build.gradle (App level) file
 
  
==== Manifest File ====
 
* Add the following permissions on the project’s ''AndroidManifest.xml'' file.
 
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
<uses-permission android:name="android.permission.INTERNET"/></syntaxhighlight>
 
<uses-permission android:name="android.permission.INTERNET"/></syntaxhighlight>
For more details to handle runtime permissions in Android versions, please visit [https://developer.android.com/training/permissions/requesting.html]. 
+
3) Add Google Play Services lib into dependencies as Nielsen AppSDK uses the following packages/classes from the Google Play service.
 
+
Libraries:
* In <code>AndroidManifest.xml </code>under <application> node add the following metadata
+
* com.google.android.gms:play-services
 
+
Requiered Google Play Service CLasses and Packages :
<syntaxhighlight lang="java"><meta-data
 
android:name="com.google.android.gms.version"
 
android:value="@integer/google_play_services_version"/></syntaxhighlight>
 
 
 
* App SDK checks to see if there is a Google service available and updated.
 
* If not available or updated, App SDK will not use this service when executing its functions and will make reference to missing imports and the app will not be compiled.
 
 
 
==== Library ====
 
Nielsen App SDK uses the following packages/classes from the Google Play service.
 
* google-play-services_lib
 
 
 
==== Classes/package ====
 
 
* com.google.android.gms.ads.identifier.AdvertisingIdClient;
 
* com.google.android.gms.ads.identifier.AdvertisingIdClient;
 
* com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
 
* com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
Line 84: Line 41:
 
* com.google.android.gms.common.GooglePlayServicesNotAvailableException;
 
* com.google.android.gms.common.GooglePlayServicesNotAvailableException;
  
== SDK Initialization ==
+
4) Once the files are in place, import com.nielsen.app.sdk to the java source code and start accessing the public interface.<br />
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object, which can be used simultaneously without any issue. The sharedInstance API that creates a singleton object was deprecated prior to version 5.1.1. (Version 4.0 for Android)
+
<syntaxhighlight lang="java">import com.nielsen.app.sdk.*;</syntaxhighlight><br />
 +
<br />
 +
 
 +
Notes:
 +
*The Nielsen App SDK (located in the "com.nielsen.app.sdk" package) class is the primary application interface to the Nielsen App SDK on Android.
 +
*The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.
 +
*Nielsen App SDK is compatible with Android OS versions 2.3+.
 +
*Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.
 +
*The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 4.0 and later will support it natively).
 +
*If the player application uses a 3rd party media player implementing its own HLS/MPEG-DASH stack, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.
 +
 
 +
== Step 2: Create SDK Instance ==
 +
The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object when needed, which can then be used simultaneously. '''For the general use case where only one video is played at the same time in the App, a single instance of SDK object can then be used to play back and measure all watched streams one after another.'''
  
 
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.
 
The following table contains the list of arguments that can be passed via the AppInfo JSON schema.
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Parameter / Argument !! Description !! Source !! Required? !! Example
+
! Parameter / Argument !! Description !! Source !! Required !! Example
 
|-
 
|-
| appid || Unique Nielsen ID for the application. The ID is a GUID data type. If you did not receive your App ID, let us know and we will provide you. || Nielsen-specified || Yes || PXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+
| appid || Unique id for the application assigned by Nielsen. It is GUID data type.|| Nielsen-specified || || "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
 +
|-
 +
| appname || Name of the application || '''value is automatically populated through App Name included in the App Resource File''' ||  || "Nielsen Sample App"
 +
|-
 +
| appversion || Current version of the app used || '''value is automatically populated through App Name included in the App Resource File''' ||  || "1.0.2"
 
|-
 
|-
 
| nol_devDebug || Enables Nielsen console logging. Only required for testing
 
| nol_devDebug || Enables Nielsen console logging. Only required for testing
|| Nielsen-specified || Optional || "DEBUG"
+
|| Nielsen-specified || || "DEBUG"
 
|}
 
|}
 +
<br />
  
== Debug flag for development environment ==
+
1) AppSDK() is no longer a singleton object and should be created as below.
Player application developers / integrators can use Debug flag to check whether an App SDK API call made is successful. To activate the Debug flag,
+
<syntaxhighlight lang="java">
Pass the argument <code>@"nol_devDebug":@"INFO"</code>, in the JSON string . The permitted values are:
+
try{
 
 
* '''INFO''': Displays the API calls and the input data from the application (validate player name, app ID, etc.). It can be used as certification Aid.
 
* '''WARN''': Indicates potential integration / configuration errors or SDK issues.
 
* '''ERROR''': Indicates important integration errors or non-recoverable SDK issues.
 
* '''DEBUG''': Debug logs, used by the developers to debug more complex issues.
 
 
 
Once the flag is active, it logs each API call made and the data passed. The log created by this flag is minimal.
 
<blockquote>'''Note''': DO NOT activate the Debug flag in a production environment.</blockquote>
 
 
 
==== Sample SDK Initialization Code ====
 
[[AppSDK()]] is no longer a singleton object and should be initialized as below.
 
 
 
'''Initialization of App SDK object through a JSON object'''
 
<syntaxhighlight lang="java">try
 
{
 
 
   // Prepare AppSdk configuration object (JSONObject)
 
   // Prepare AppSdk configuration object (JSONObject)
 
   JSONObject appSdkConfig = new JSONObject()
 
   JSONObject appSdkConfig = new JSONObject()
           .put("appid", "PDA7D5EE6-B1B8-XXXX-XXXX-2A788BCXXXCA")
+
           .put("appid", "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
 
           .put("nol_devDebug", "DEBUG"); // only for debug builds
 
           .put("nol_devDebug", "DEBUG"); // only for debug builds
  
// Pass appSdkConfig to the AppSdk constructor
+
        // Pass appSdkConfig to the AppSdk constructor
mAppSdk = new AppSdk(appContext, appSdkConfig, appSdkListener);
+
        mAppSdk = new AppSdk(appContext, appSdkConfig, this);
 
}
 
}
catch (JSONException e)
+
catch (JSONException e){
{
+
        Log.e(TAG, "Couldn’t prepare JSONObject for appSdkConfig", e);
  Log.e(TAG, "Couldn’t prepare JSONObject for appSdkConfig", e);
+
}
 +
</syntaxhighlight>
 +
2) implement IAppNotifier into your activity like
 +
<syntaxhighlight lang="java">public class MainActivity extends AppCompatActivity implements IAppNotifier
 +
</syntaxhighlight>
 +
3) implement callback
 +
<syntaxhighlight lang="java">@Override
 +
public void onAppSdkEvent(long timestamp, int code, String description){
 +
  Log.d(TAG, "SDK callback onAppSdkEvent " + description);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Here, <code>appContext</code> is the App context object and <code>appSdkConfig</code> is JSON object for holding the parameters (<code>appid</code>) the App passes to the Nielsen App SDK via a JSON string. The appid is obtained from Nielsen operational support and is unique to the app.
 
  
 +
So whole Activity will look like
 +
<syntaxhighlight lang="java">
 +
package com.example.josefvancura.nlsdemotmp;
  
The integration of Nielsen App SDK will depend on type of client app.<br />
+
import android.content.Context;
* Ensure that SDK files (AppSdk.jar and libAppSdk.so [App SDK 1.2 Only]) are included under the App’s project and the App SDK is linked to the App (the setting to link App SDK to the App can be found on property page of the App’s project).
+
import android.support.v7.app.AppCompatActivity;
 +
import android.os.Bundle;
 +
import android.util.Log;
  
<!-- == Initializing the Nielsen AppSDK to measure the Viewability ==
+
import com.nielsen.app.sdk.*;
The integrator to support the viewability metrics in the application has to provide a tag value of the player view to let Nielsen AppSDK know that there is a player that needs to be tracked. It’s called the ‘containerId’ and it should be passed in application info dictionary as string while initializing the Nielsen AppSDK.
 
  
==== Android ====
+
import org.json.JSONException;
{| class="wikitable"
+
import org.json.JSONObject;
|-
+
 
! # !! Parameter Name !! Description !! Supported Values !! Example
+
public class MainActivity extends AppCompatActivity implements IAppNotifier {
|-
+
 
| 1 || containerId ||View ID of the UI element used as player view in application. getId() method of View class can be used to get this value. ||A positive integer used to identify the view. || 2131558561
+
    private AppSdk mAppSdk = null;
|}
+
    private String TAG = "MainActivity";
 +
 
 +
    @Override
 +
    protected void onCreate(Bundle savedInstanceState) {
 +
        super.onCreate(savedInstanceState);
 +
        setContentView(R.layout.activity_main);
 +
 
 +
        Context context = getApplicationContext();
 +
 
 +
        try{
 +
            // Prepare AppSdk configuration object (JSONObject)
 +
            JSONObject appSdkConfig = new JSONObject()
 +
                    .put("appid", "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
 +
                    .put("nol_devDebug", "DEBUG"); // only for debug builds
 +
 
 +
            // Pass appSdkConfig to the AppSdk constructor
 +
            mAppSdk = new AppSdk(context, appSdkConfig, this ); // Notifier - activity implements IAppNotifier, callback in onAppSdkEvent()
 +
 
 +
        }
 +
        catch (JSONException e){
 +
            Log.e(TAG, "Couldn’t prepare JSONObject for appSdkConfig", e);
 +
        }
  
==== iOS ====
+
    }
{| class="wikitable"
 
|-
 
! # !! Parameter Name !! Description !! Supported Values !! Example
 
|-
 
| 1 || containerId ||The tag of the UIView that represents the Player View ||The string value representing the NSInteger value with maximum value of NSIntegerMax that is related on 32- or 64-bit applications. || "100" <br> "2131558561"
 
|}
 
  
For iOS it is required to link additional frameworks that are needed for viewability engine:<br>
+
    @Override
<code>JavaScriptCore.framework</code> <br>
+
    public void onAppSdkEvent(long timestamp, int code, String description) {
<code>WebKit.framework</code>
+
        Log.d(TAG, "SDK callback onAppSdkEvent " + description);
 +
    }
  
The Nielsen AppSDK uses a tracking WebView (TWV) approach.  For more information on Viewability, please refer to [https://engineeringportal.nielsen.com/docs/Implementing_Viewability_with_AppSDK Implementing Viewability with AppSDK.]
+
}
-->
+
</syntaxhighlight>
  
== APP SDK Error & Event Codes ==
+
==== APP SDK Error & Event Codes ====
 
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.
 
To view the Error and Event codes for iOS and Android, please review the [[APP SDK Event Codes|App SDK Event Code]] Reference page.
  
== Create Metadata Objects ==
+
==== Life cycle of SDK instance ====
 +
Life cycle of SDK instance includes four general states:
 +
# ""Initial state"" – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the ""Initial state"".
 +
# ""Idle state"" – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.
 +
# ""Processing state"" – The SDK instance is processing playing information. API calls "play" and "loadMetadata" move the SDK instance into this state. In this state, the SDK instance will be able to process the API calls (see below)
 +
# ""Disabled state"" – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.
 +
## Initialization fails
 +
## <code>appDisableApi</code> is called
 +
<syntaxhighlight lang="objective-c">
 +
@property (assign) BOOL appDisableApi;
 +
</syntaxhighlight>
 +
 
 +
== Step 3: Create Metadata Objects ==
 
The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.
 
The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.
 
* NSDictionary object
 
* NSDictionary object
Line 221: Line 219:
 
||
 
||
 
 
 +
|-style="background-color:#d0f6f8;"
 +
|stationId || Unique Gracenote Station ID generated by Nielsen that uniquely identifies a live channel
 +
||
 +
provided by Nielsen
 +
||
 +
 +
|-style="background-color:#d0f6f8;"
 +
|islivestn || Indicates if a stream is playing on a live channel
 +
||
 +
:
 +
* "y" playing on a live channel
 +
* "n" otherwise i.e. VoD
 +
||
 +
 +
|-style="background-color:#d0f6f8;"
 +
|pbstarttm || Playback Start Time (UTC): Unix timestamp in seconds matching the broadcast time for Content and Ad when a user starts and joins a live stream (seconds since Jan-1-1970 UTC)
 +
||
 +
i.e. "1631098029" for live stream and ""(empty string) for a VoD.
 +
||
 +
 +
|-
 +
| subbrand || vcid/sub-brand/Channel  ID – value is automatically populated through provided AppID. In order to override the sub-brand configured to the App ID, value can be passed here (e.g. multiple sub-brands/Channels in the App)
 +
||
 +
provided by Nielsen
 +
||
 +
 
|}
 
|}
  
Line 234: Line 258:
 
|-
 
|-
 
| assetid || unique ID assigned to Ad || custom<br>(no [[Special Characters]]) || ✓
 
| assetid || unique ID assigned to Ad || custom<br>(no [[Special Characters]]) || ✓
 +
|-style="background-color:#d0f6f8;"
 +
|stationId || Unique Gracenote Station ID generated by Nielsen that uniquely identifies a live channel
 +
||
 +
provided by Nielsen
 +
||
 +
 +
|-style="background-color:#d0f6f8;"
 +
|islivestn || Indicates if a stream is playing on a live channel
 +
||
 +
:
 +
* "y" playing on a live channel
 +
* "n" otherwise i.e. VoD
 +
||
 +
 +
|-style="background-color:#d0f6f8;"
 +
|pbstarttm || Playback Start Time (UTC): Unix timestamp in seconds matching the broadcast time for Content and Ad when a user starts and joins a live stream (seconds since Jan-1-1970 UTC)
 +
||
 +
i.e. "1631098029" for live stream and ""(empty string) for a VoD.
 +
||
 +
 +
|-
 +
| subbrand || vcid/sub-brand/Channel  ID – value is automatically populated through provided AppID. In order to override the sub-brand configured to the App ID, value can be passed here (e.g. multiple sub-brands/Channels in the App) || provided by Nielsen || ✓
 
|}
 
|}
  
Line 239: Line 285:
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
JSONObject channelInfo = new JSONObject()
 
JSONObject channelInfo = new JSONObject()
     .put("channelname","My Channel Name 1")
+
     .put("channelName","My Channel Name 1")
  
 
JSONObject contentMetadata = new JSONObject()
 
JSONObject contentMetadata = new JSONObject()
Line 249: Line 295:
 
   .put("airdate", "20200713 10:22:00")
 
   .put("airdate", "20200713 10:22:00")
 
   .put("isfullepisode", "y")
 
   .put("isfullepisode", "y")
   .put("adloadtype", "2");
+
   .put("adloadtype", "2")
 +
  .put("subbrand", "c05")
 +
  .put("stationId", "TESTXXYYSSWWLL")
 +
  .put("islivestn", "y")
 +
  .put("pbstarttm", "1631098029");
  
 
JSONObject adMetadata = new JSONObject()
 
JSONObject adMetadata = new JSONObject()
 
   .put("assetid", "unique_postroll_ad_id")
 
   .put("assetid", "unique_postroll_ad_id")
   .put("type", "postroll");
+
   .put("type", "postroll"
 +
  .put("subbrand", "c05")
 +
  .put("stationId", "TESTXXYYSSWWLL")
 +
  .put("islivestn", "y")
 +
  .put("pbstarttm", "1631098029");
  
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Sequence of Calls ==
+
== Step 4: Start the Measurement ==
=== play ===
+
 
Use [[DCR_Video_APP_SDK#play|play]] to pass the channel descriptor information through channelName parameter when the user taps the '''Play''' button on the player.
+
=== Overview of SDK API Calls ===
<syntaxhighlight lang="java">    public void play(JSONObject channelInfo);</syntaxhighlight>
+
 
 +
==== play ====
 +
The play method prepares the SDK for reporting once an asset has loaded and playback has begun. Use play to pass the channel descriptor information through channelName parameter when the user taps the ""Play"" button on the player. Call play only when initially starting the video.
  
=== loadMetadata ===
+
<syntaxhighlight lang="java">mAppSdk.play(JSONObject channelInfo);</syntaxhighlight>
<syntaxhighlight lang="java">public void loadMetadata(JSONObject contentMetadata);</syntaxhighlight>
 
  
=== playheadPosition ===
+
==== loadMetadata ====
<syntaxhighlight lang="java">
+
Needs to be called at the beginning of each asset, pass JSON object for relevant content or ad. Make sure to pass as 1st loadMetadata for content at the begining of playlist - see below API call sequence examples.
public void setPlayheadPosition(long position)
+
<syntaxhighlight lang="java">mAppSdk.loadMetadata(JSONObject contentMetadata);</syntaxhighlight>
</syntaxhighlight>
 
  
=== stop ===
+
==== playheadPosition ====
<syntaxhighlight lang="java">public void stop()</syntaxhighlight>
+
<pre style="background-color:#d0f6f8">
 +
Note: "setPlayheadPosition" has to be called every second and the value passed should match the broadcast time for live channel.
 +
</pre>
 +
* VOD: current position in seconds. Pass whole number that increments only by 1 like 0,1,2,3... <br/>
 +
* Live: Unix timestamp matching the broadcast time for Content and Ad (seconds since Jan-1-1970 UTC). Pass whole number that increments only by 1 like 1631098029,1631098030,1631098031,1631098032,... <br/>
  
=== end ===
+
<syntaxhighlight lang="Java">mAppSdk.setPlayheadPosition(long videoPositon);</syntaxhighlight>
When content stop is initiated and content cannot be resumed from the same position (it can only be restarted from the beginning of stream).
 
<syntaxhighlight lang="java">public void end()</syntaxhighlight>
 
  
== Configure API Calls ==
+
==== sendID3 ====
 +
Needs to be called when ID3 Tags are included in the Video Stream.
 +
<syntaxhighlight lang="Java">mAppSdk..sendID3(String id3);</syntaxhighlight>
  
=== Sample API Sequence ===
+
<blockquote>
A Sample API sequence could follow this flow:
+
ID3 Tags are parsed from the Video Stream, refer to the DK Reference Implementation [http://nielsenonlinesupport.com/dk/index.htm sdkRefImplDK] on how to parse ID3 Tags included in a sample HLS Stream.
{| class="wikitable"
+
For further technical details, please contact your Technical Account Manager (TAM).
|-
+
</blockquote>
! Type !! Sample code !! Description
 
|-
 
|On App Start||<code>[nielsenMeter loadMetadata: contentMetadata];</code> || // contentMetadata Object contains the JSON metadata for the impression
 
|-
 
| rowspan="2" | Start of stream || <code>[nielsenMeter play];</code> || // call at start of each new stream
 
|-
 
| <code>[nielsenMeter loadMetadata: contentMetadataObject];</code> || // contentMetadataObject contains the JSON metadata for the content being played
 
|-
 
| Content || <code>[nielsenMeter setplayheadPosition: position];</code> || // playheadPosition is position of the playhead while the content is being played
 
|-
 
| End of Stream || <code>[nielsenMeter end];</code> || // Content playback is completed.
 
|}
 
  
=== SDK Events ===
+
==== stop ====
{| class="wikitable"
+
Call when
|-
+
* ads complete playing
! Event !! Parameter !! Description
+
* when a user pauses playback
|-
+
* upon any user interruption scenario - see bellow chapter Interruption scenario
| 'play' || || Call at start of each new stream
 
|-
 
| 'loadMetadata' || content/ad metadata object || Needs to be called at the beginning of each asset
 
|-
 
| 'setPlayheadPosition' || playhead position as integer<br/>
 
VOD: || current position in seconds <br/>
 
Live: current Unix timestamp (seconds since Jan-1-1970 UTC) <br/>
 
Note: 'setPlayheadPosition' has to be called every second
 
||
 
Pass playhead position every second during playback
 
|-
 
| 'stop' || playhead position || Call during any interruption to content or Ad playback and at the end of each Ad.
 
|-
 
| 'end' || playhead position in seconds || Call when the current video asset completes playback and pass the playhead position. <br/>
 
Example: At the end of the content stream, if the user switches to another piece of content, when the browser is refreshed or closed.
 
|}
 
<blockquote>Note: For livestream, send the Unix timestamp; for VOD send the time in seconds as integer. The final playhead position must be sent for the current asset being played before calling <code>'''stop'''</code>, <code>'''end'''</code> or<code> '''loadmetadata'''</code>,.</blockquote>
 
  
=== Life cycle of SDK instance ===
+
<syntaxhighlight lang="java">mAppSdk.stop();</syntaxhighlight>
Life cycle of SDK instance includes four general states:
 
# '''Initial state''' – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the '''Initial state'''.
 
# '''Idle state''' – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.
 
# '''Processing state''' – The SDK instance is processing playing information. The <code>'''play'''</code> and <code>'''loadMetadata''' </code> calls move the SDK instance into this state. In this state, the SDK instance will be able to process the following calls.
 
## <code>'''setplayheadPosition'''</code> – Call this API every one second when playhead position timer is fired.  If a LIVE event, use the current Unix timestamp (seconds since Jan-1-1970 UTC).
 
## <code>'''stop'''</code> – Call this API when the playback is paused, switches between content and ad (within the same content playback) or encounters interruptions.
 
## <code>'''end'''</code> – Call when content completes. When called, the SDK instance exits from Processing state.
 
# '''Disabled state''' – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.
 
## Initialization fails
 
## <code>'''appDisableApi'''</code> is set to <code>true</code>
 
  
<blockquote>'''Note:''' For API Version 5.1 and above, App SDK will fire data pings and continue measurement even after the user has opted out from Nielsen measurement on a device. The data ping will be marked as opted-out ping.
+
==== end ====
 +
Call when the content asset completes playback. Stops measurement progress.
 +
<syntaxhighlight lang="java">mAppSdk.end();</syntaxhighlight>
 +
<br />
  
'''Note''': In case of any interruptions during playback due to alarm, calendar, call, flight mode, Wi-Fi toggle, channel change, etc., call [[stop]] to stop the measurement.
 
* As soon as the playback resumes, <code>'''loadMetadata''' </code> and  <code>'''playheadPosition'''</code> </blockquote>
 
  
=== API Call Sequence ===
+
=== Start the Measurement ===
==== Use Case 1: Content has no Advertisements ====
+
In order to start the measurement, follow the 3 first steps below for Content without Ads. When terminating the Content playback call <code>end</code> to terminate the Content Measurement for the given asset.
Call [[play()]] at start of stream
 
  
Call [[loadMetadata()]] with JSON metadata for content as below.
 
<syntaxhighlight lang="json">{
 
  "type": "content",
 
  "assetid": "vid345-67483",
 
  "program": "ProgramName",
 
  "title": "Program S3, EP1",
 
  "length": "3600",
 
  ...
 
}</syntaxhighlight>
 
Call [[setPlayheadPosition()]] every one second until a pause / stop.
 
Use the sample API sequence below as a reference to identify the specific events that need to be called during content playback without ads.
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Type !! Sample code !! Description
+
! Playlist !! Sample code !! Description
 
|-
 
|-
| rowspan="2" | Start of stream || <code>mAppSdk.play(); </code> || // Call at start of each new stream
+
| rowspan="2" | 1. Start of stream || <code>play(channelName)</code> || channelName contains JSON metadata of channel/video name being played
 
|-
 
|-
| <code>mAppSdk.loadMetadata(contentMetaDataObject);</code> || // contentMetadataObject contains the JSON metadata for the content being played
+
| <code>loadMetadata(contentMetadataObject)</code> || contentMetadataObject contains the JSON metadata for the content being played
 
|-
 
|-
| Content || <code>mAppSdk.setPlayheadPosition(playheadPosition);</code> || // position is position of the playhead while the content is being played
+
| 2. Content is playing || <code>playheadPosition(position)</code> || playheadPosition is position of the playhead while the content is being played
 
|-
 
|-
| Interruption || <code>mAppSdk.stop();</code> || // call stop when content playback is interrupted
+
| || <code>sendID3(id3)</code> || id3 is an ID3 Tag parsed from the Video Stream, pass ID3 Tag immediately to SDK when found
 
|-
 
|-
| rowspan="2" | Resume Content || <code>mAppSdk.loadMetadata(contentMetaDataObject);</code>  || // Call loadMetadata and pass content metadata object when content resumes
+
| 3. End of Stream || <code>end</code> || Content playback is completed.
|-
 
|<code>mAppSdk.setPlayheadPosition(playheadPosition);</code> || // continue pasing playhead position every second starting from position where content is resumed
 
|-
 
| End of Stream || <code>mAppSdk.end();</code> || // Content playback is completed.
 
 
|}
 
|}
  
Line 383: Line 387:
 
In case of encountering one of the above interruptions, the player application needs to
 
In case of encountering one of the above interruptions, the player application needs to
 
* Call <code>stop</code> immediately (except when content is buffering) and withhold sending playhead position.
 
* Call <code>stop</code> immediately (except when content is buffering) and withhold sending playhead position.
* Start sending pings –  <code>loadMetadata</code> and <code>playheadPosition</code> for the new viewing session, once the playback resumes.
+
* Once the playback resumes, start sending pings <code>playheadPosition</code> for the new viewing session.
 
Please see the [[Digital Measurement FAQ]] for more details
 
Please see the [[Digital Measurement FAQ]] for more details
  
== SDK Integration Architecture Diagram ==
+
== Step 6: Review SDK Integration Architecture Diagram ==
  
 
=== For Content Playback ===
 
=== For Content Playback ===
  
[[File:nlsn-sdk-achitecture-diagram_content.png||SDK Integration Architecture Diagram - Content]]
+
[[File:nlsn-sdk-achitecture-diagram-content-v1.png||SDK Integration Architecture Diagram - Content]]
  
 
=== For Ad Playback ===
 
=== For Ad Playback ===
[[File:nlsn-sdk-achitecture-diagram_ad.png||SDK Integration Architecture Diagram - Ad]]
+
[[File:nlsn-sdk-achitecture-diagram-ad-v1.png||SDK Integration Architecture Diagram - Ad]]
  
== Privacy ==
+
== Step 7 : Disclose Nielsen Privacy Statement ==
The privacy section will be added soon.
+
The App SDK uses Mobile Ad IDs (Android ID or IDFA) which are fully hashed on the device before being sent to Nielsen (Nielsen never receives un-hashed values).
 +
Users retain the possibility to oppose the use of Mobile Ad IDs, or to reset them, by using the functionality provided by the mobile operating system (iOS or Android).
  
 +
In order to disclose Nielsen measurement privacy statement, please include the following items in your privacy policy:
 +
* A notice that the player includes third party measurement software that allows users to contribute to market research.
 +
* A link to the Nielsen Digital Measurement Privacy Policy located at https://sites.nielsen.com/priv/browser/dk/da/DigitalMeasurement.html .
 +
 +
== Step 8 : Review the Reference Implementation for VoD and Live Streams ==
 +
 +
The Reference Implementation covers VoD and Live use cases.
 +
It also covers DAI (Dynamic Ad Insertion) with  preroll Ad.
 +
 +
Download the Reference Implementation for Android [https://nielsenonlinesupport.com/dk/android/DKRefPLAYER.zip DKRefPLAYER].
 +
Unzip and open the project in Android Studio, then run it i.e. in the simulator or on Android device and then filter the Logcat output with ">>>" in order to see only relevant Nielsen SDK API Calls, as below:
 +
 +
<syntaxhighlight lang="java">
 +
2021-04-08 15:11:27.075  D/NielsenInit: ====>>> SDK CALL : class NielsenInit :: Create new AppSdk() Instance.
 +
2021-04-08 15:11:27.568  D/NielsenInit: ====>>> SDK EVENT - onAppSdkEvent: Description = Nielsen App SDK is initiated. AppSdk.jar aa.8.0.0.0_gsxaon. App SDK was successfully initiatedCode l param : 1617887487Code i param 2000
 +
2021-04-08 15:11:29.497  D/NielsenInit: ====>>> SDK EVENT - onAppSdkEvent: Description = Nielsen App SDK has started up. AppSdk.jar aa.8.0.0.0_gsxaon. Config file successfully loaded and parsed.Code l param : 1617887489Code i param 2001
 +
2021-04-08 15:11:42.736  D/MainActivity: ====>>> SDK CALL :  appSdk.play(sdkMethods.loadChannelInfo());
 +
2021-04-08 15:11:42.738  D/MainActivity: ====>>> SDK CALL : onPrepared() : appSdk.loadMetadata(data)
 +
2021-04-08 15:11:43.065  D/MainActivity: ====>>> Media Player Event : onInfo ();what = 3
 +
2021-04-08 15:11:43.065  D/MainActivity: ====>>> Media Player Event :  first video frame pushed for rendering.
 +
2021-04-08 15:11:43.747  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 0 / 224
 +
2021-04-08 15:11:44.752  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 1 / 224
 +
2021-04-08 15:11:45.759  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 2 / 224
 +
2021-04-08 15:11:46.764  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 3 / 224
 +
2021-04-08 15:11:47.767  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 4 / 224
 +
2021-04-08 15:11:48.772  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 5 / 224
 +
2021-04-08 15:11:49.777  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 6 / 224
 +
2021-04-08 15:11:50.781  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 7 / 224
 +
2021-04-08 15:11:51.819  D/MainActivity: ====>>> SDK CALL :  appSdk.setPlayheadPosition(mCurrentPosition): @ 8 / 224
 +
2021-04-08 15:11:51.821  D/MainActivity: ====>>> Activity onPause()
 +
2021-04-08 15:11:52.668  D/MainActivity: ====>>>: Activity onDestroy()
 +
2021-04-08 15:11:52.668  D/MainActivity: ====>>> SDK CALL : terminateNielsenSDK () :appSdk.end();
 +
</syntaxhighlight>
  
== Step 7 :  Test your player by yourself ==
+
== Step 9 :  Test your player by yourself ==
 
=== Guide ===
 
=== Guide ===
 
1. Connect your PC and test device (tablet or phone) via same router.<br />
 
1. Connect your PC and test device (tablet or phone) via same router.<br />
 
2. PC side: run Proxy sw (like Charles) and get local IP<br />
 
2. PC side: run Proxy sw (like Charles) and get local IP<br />
3. Test device: modify Wifi setting to pass through Proxy IP from add 2<br />
+
3. Test device: modify Wifi setting to pass through Proxy IP from step 2.<br />
 
4. Test device: run your player, launch video<br />
 
4. Test device: run your player, launch video<br />
 
5. PC side: filter traffic by "nmr" and confirm presence of GN pings<br />
 
5. PC side: filter traffic by "nmr" and confirm presence of GN pings<br />
  
 
=== Example of GN ping ===
 
=== Example of GN ping ===
<code></code>
+
<code><nowiki>https://secure-dmk.nmrodam.com/cgi-bin/gn?prd=dcr&ci=us-500207&ch=us-500207_c77_P&asn=defChnAsset&fp_id=&fp_cr_tm=&fp_acc_tm=&fp_emm_tm=&ve_id=&devmodel=&manuf=&sysname=&sysversion=&sessionId=zlmmxkq867zt4bpnumlyz6dpn9hyp1610980356&tl=Episode%201&prv=1&c6=vc%2Cc77&ca=us-500207_c77_VID5556674-123456&cg=TAMSample%20DK&c13=asid%2CP10DF14BA-937E-436D-99DF-ED39A0422387&c32=segA%2CNA&c33=segB%2CNA&c34=segC%2CNA&c15=apn%2C&plugv=&playerv=&sup=1&segment2=&segment1=&forward=0&ad=0&cr=4_00_99_V1_00000&c9=devid%2C&enc=true&c1=nuid%2C999&at=view&rt=video&c16=sdkv%2Cbj.6.0.0&c27=cln%2C0&crs=&lat=&lon=&c29=plid%2C16109803568088038&c30=bldv%2C6.0.0.563&st=dcr&c7=osgrp%2C&c8=devgrp%2C&c10=plt%2C&c40=adbid%2C&c14=osver%2CNA&c26=dmap%2C1&dd=&hrd=&wkd=&c35=adrsid%2C&c36=cref1%2C&c37=cref2%2C&c11=agg%2C1&c12=apv%2C&c51=adl%2C0&c52=noad%2C0&sd=170&devtypid=&pc=NA&c53=fef%2Cy&c54=oad%2C20200713%2010%3A22%3A00&c55=cref3%2C&c57=adldf%2C2&ai=VID5556674-123456&c3=st%2Cc&c64=starttm%2C1610980392&adid=VID5556674-123456&c58=isLive%2Cfalse&c59=sesid%2Cgezrb92q4i9b9jg7acxgn783gjw0a1610980365&c61=createtm%2C1610980392&c63=pipMode%2C&c68=bndlid%2C&nodeTM=&logTM=&c73=phtype%2C&c74=dvcnm%2C&c76=adbsnid%2C&c77=adsuprt%2C2&uoo=&evdata=&c71=ottflg%2C0&c72=otttyp%2Cnone&c44=progen%2C&davty=0&si=http%3A%2F%2Fnielsenonlinesupport.com%2Fdk%2Findex.htm&c66=mediaurl%2Cassets%252FRTVOD_C3%252Fprog_index.m3u8&c62=sendTime%2C1610980392&rnd=714644</nowiki></code>
  
== Step 8 :  Provide your app for certification ==
+
== Step 10 :  Provide your app for certification ==
 
Once ready please send your application to Nielsen local staff for certification.
 
Once ready please send your application to Nielsen local staff for certification.
  
== Step 9 :  Going Live ==
+
== Step 11 :  Going Live ==
After the integration has been certified (but not prior that), disable debug logging by deleting {nol_sdkDebug: "DEBUG"} from initialization call - see Step 2.
+
After the integration has been certified (but not prior that), disable debug logging by deleting {nol_devDebug: "DEBUG"} from initialization call - see Step 2.

Revision as of 09:04, 10 February 2022

Engineering Portal breadcrumbArrow.png Digital breadcrumbArrow.png International DCR breadcrumbArrow.png DCR Denmark Video Android SDK

Overview

The Nielsen SDK is one of multiple framework SDKs that Nielsen provides to enable measuring linear (live) and on-demand TV viewing using TVs, mobile devices, etc. The App SDK is the framework for mobile application developers to integrate Nielsen Measurement into their media player applications. It supports a variety of Nielsen Measurement Products like It supports a variety of Nielsen Measurement Products like Digital in TV Ratings (DTVR), Digital Content Ratings (DCR), and Digital Ad Ratings (DAR). Nielsen SDKs are also equipped to measure static content and can track key life cycle events of an application like:

  • Application launch events and how long app was running
  • Time of viewing a sub section / page in the application.

Prerequisites

Before you start the integration, you will need:

Item Description Source
"App ID (appid)" Unique ID assigned to the player/site and configured by product. Contact Nielsen
"Nielsen SDK" Includes SDK frameworks and "sample implementation"; "See Android SDK Release Notes" Download

Step 1: Setting up your Android Development Environment


1) Ensure to unzip the Nielsen App SDK zip file and copy the "AppSdk.jar" into the app/libs folder on the App’s project. Add it as dependency.
2) Add the following permissions on the project’s "AndroidManifest.xml" file.

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

3) Add Google Play Services lib into dependencies as Nielsen AppSDK uses the following packages/classes from the Google Play service. Libraries:

  • com.google.android.gms:play-services

Requiered Google Play Service CLasses and Packages :

  • com.google.android.gms.ads.identifier.AdvertisingIdClient;
  • com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
  • com.google.android.gms.common.ConnectionResult;
  • com.google.android.gms.common.GooglePlayServicesUtil;
  • com.google.android.gms.common.GooglePlayServicesRepairableException;
  • com.google.android.gms.common.GooglePlayServicesNotAvailableException;

4) Once the files are in place, import com.nielsen.app.sdk to the java source code and start accessing the public interface.

import com.nielsen.app.sdk.*;



Notes:

  • The Nielsen App SDK (located in the "com.nielsen.app.sdk" package) class is the primary application interface to the Nielsen App SDK on Android.
  • The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package.
  • Nielsen App SDK is compatible with Android OS versions 2.3+.
  • Clients can control / configure the protocol to be used – HTTPS or HTTP to suit their needs.
  • The Android OS hosting the App SDK should use a media player supporting HLS streaming (Android 4.0 and later will support it natively).
  • If the player application uses a 3rd party media player implementing its own HLS/MPEG-DASH stack, then the minimum Android version will be limited to version 2.3, since the SDK depends on Google Play support to work properly.

Step 2: Create SDK Instance

The latest version of the Nielsen App SDK allows instantiating multiple instances of the SDK object when needed, which can then be used simultaneously. For the general use case where only one video is played at the same time in the App, a single instance of SDK object can then be used to play back and measure all watched streams one after another.

The following table contains the list of arguments that can be passed via the AppInfo JSON schema.

Parameter / Argument Description Source Required Example
appid Unique id for the application assigned by Nielsen. It is GUID data type. Nielsen-specified "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
appname Name of the application value is automatically populated through App Name included in the App Resource File "Nielsen Sample App"
appversion Current version of the app used value is automatically populated through App Name included in the App Resource File "1.0.2"
nol_devDebug Enables Nielsen console logging. Only required for testing Nielsen-specified "DEBUG"


1) AppSDK() is no longer a singleton object and should be created as below.

try{
  // Prepare AppSdk configuration object (JSONObject)
  JSONObject appSdkConfig = new JSONObject()
          .put("appid", "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
          .put("nol_devDebug", "DEBUG"); // only for debug builds

         // Pass appSdkConfig to the AppSdk constructor
         mAppSdk = new AppSdk(appContext, appSdkConfig, this);
}
catch (JSONException e){
         Log.e(TAG, "Couldn’t prepare JSONObject for appSdkConfig", e);
}

2) implement IAppNotifier into your activity like

public class MainActivity extends AppCompatActivity implements IAppNotifier

3) implement callback

@Override
public void onAppSdkEvent(long timestamp, int code, String description){
  Log.d(TAG, "SDK callback onAppSdkEvent " + description);
}

So whole Activity will look like

package com.example.josefvancura.nlsdemotmp;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.nielsen.app.sdk.*;

import org.json.JSONException;
import org.json.JSONObject;

public class MainActivity extends AppCompatActivity implements IAppNotifier {

    private AppSdk mAppSdk = null;
    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Context context = getApplicationContext();

        try{
            // Prepare AppSdk configuration object (JSONObject)
            JSONObject appSdkConfig = new JSONObject()
                    .put("appid", "PXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
                    .put("nol_devDebug", "DEBUG"); // only for debug builds

            // Pass appSdkConfig to the AppSdk constructor
            mAppSdk = new AppSdk(context, appSdkConfig, this ); // Notifier - activity implements IAppNotifier, callback in onAppSdkEvent()

        }
        catch (JSONException e){
            Log.e(TAG, "Couldn’t prepare JSONObject for appSdkConfig", e);
        }

    }

    @Override
    public void onAppSdkEvent(long timestamp, int code, String description) {
        Log.d(TAG, "SDK callback onAppSdkEvent " + description);
    }

}

APP SDK Error & Event Codes

To view the Error and Event codes for iOS and Android, please review the App SDK Event Code Reference page.

Life cycle of SDK instance

Life cycle of SDK instance includes four general states:

  1. ""Initial state"" – The SDK is not initialized and hence, not ready to process playing information. Once the SDK is moved out of this state, it needs instantiation of the new SDK instance in order to get the instance in the ""Initial state"".
  2. ""Idle state"" – The SDK is initialized and is ready to process playing information. Once Initialized, the SDK instance is not processing any data, but is listening for the play event to occur.
  3. ""Processing state"" – The SDK instance is processing playing information. API calls "play" and "loadMetadata" move the SDK instance into this state. In this state, the SDK instance will be able to process the API calls (see below)
  4. ""Disabled state"" – The SDK instance is disabled and is not processing playing information. SDK instance moves into this state in one of the following scenarios.
    1. Initialization fails
    2. appDisableApi is called
@property (assign) BOOL appDisableApi;

Step 3: Create Metadata Objects

The parameters passed must be either a JSON formatted string or a NSDictionary object. The JSON passed in the SDK must be well-formed.

  • NSDictionary object
    • If an object of unexpected type is passed to the method, the error message will be logged.
    • If string has invalid JSON format, the error message will be logged.
  • JSON value must be string value.
    • This includes boolean and numeric values. For example, a value of true should be represented with "true", number value 123 should be "123".
    • All the Variable Names like appid, appname, dataSrc, title, type etc. are case-sensitive. Use the correct variable name as specified in the documentation.
  • JSON string can be prepared using either raw NSString or serialized NSDictionary.


Create channelName Metadata

channelName should remain constant throughout the completion of an episode or live stream.

Key Description Values Required
channelName Any string representing the channel/stream custom

Create Content Metadata

Content metadata should remain constant throughout the entirety of an episode/clip including when ads play.


program and title metadata values should be passed to SDK as UTF-8 strings.

Keys Description Values Required
type type of asset "content" for main content
assetid unique ID assigned to asset custom
(no Special Characters)
program name of program custom
title episode name custom
length length of content in seconds Length of content in seconds (86400 seconds for live stream (24/7). For Event-Live streams planned length. For VoD video length)
airdate the original date (local time with hh:mm:ss as 24h time stamp) content became available. This date does not change if the content is rebroadcasted on linear TV. YYYYMMDD HH:MI:SS (if not known set it to eg. "19700101 00:00:00")
isfullepisode full episode flag
  • "y" full episode (full content for a program)
  • "n" non full episode (only one part of the entire content for a program , i.e. preview, sub-episodes)

adloadtype type of Ad load
  • "1" Linear - matches TV ad load
  • "2" Dynamic - Dynamic Ad Insertion (DAI)

stationId Unique Gracenote Station ID generated by Nielsen that uniquely identifies a live channel

provided by Nielsen

islivestn Indicates if a stream is playing on a live channel
  • "y" playing on a live channel
  • "n" otherwise i.e. VoD

pbstarttm Playback Start Time (UTC): Unix timestamp in seconds matching the broadcast time for Content and Ad when a user starts and joins a live stream (seconds since Jan-1-1970 UTC)

i.e. "1631098029" for live stream and ""(empty string) for a VoD.

subbrand vcid/sub-brand/Channel ID – value is automatically populated through provided AppID. In order to override the sub-brand configured to the App ID, value can be passed here (e.g. multiple sub-brands/Channels in the App)

provided by Nielsen

Create Ad Metadata (optional for DR)

The Ad Metadata (if applicable) should be passed for each individual ad.

Note: All metadata values should be passed as UTF-8 strings.

Keys Description Values Required
type type of Ad "preroll", "midroll", "postroll"
"ad" - If specific type can not be identified.
assetid unique ID assigned to Ad custom
(no Special Characters)
stationId Unique Gracenote Station ID generated by Nielsen that uniquely identifies a live channel

provided by Nielsen

islivestn Indicates if a stream is playing on a live channel
  • "y" playing on a live channel
  • "n" otherwise i.e. VoD

pbstarttm Playback Start Time (UTC): Unix timestamp in seconds matching the broadcast time for Content and Ad when a user starts and joins a live stream (seconds since Jan-1-1970 UTC)

i.e. "1631098029" for live stream and ""(empty string) for a VoD.

subbrand vcid/sub-brand/Channel ID – value is automatically populated through provided AppID. In order to override the sub-brand configured to the App ID, value can be passed here (e.g. multiple sub-brands/Channels in the App) provided by Nielsen

MetaData Example

JSONObject channelInfo = new JSONObject()
    .put("channelName","My Channel Name 1")

JSONObject contentMetadata = new JSONObject()
   .put("assetid", "unique_content_id")
   .put("type", "content")
   .put("program", "program name")
   .put("title", "episode title")
   .put("length", "length in seconds")
   .put("airdate", "20200713 10:22:00")
   .put("isfullepisode", "y")
   .put("adloadtype", "2")
   .put("subbrand", "c05")
   .put("stationId", "TESTXXYYSSWWLL")
   .put("islivestn", "y")
   .put("pbstarttm", "1631098029");

JSONObject adMetadata = new JSONObject()
   .put("assetid", "unique_postroll_ad_id")
   .put("type", "postroll"
   .put("subbrand", "c05")
   .put("stationId", "TESTXXYYSSWWLL")
   .put("islivestn", "y")
   .put("pbstarttm", "1631098029");

Step 4: Start the Measurement

Overview of SDK API Calls

play

The play method prepares the SDK for reporting once an asset has loaded and playback has begun. Use play to pass the channel descriptor information through channelName parameter when the user taps the ""Play"" button on the player. Call play only when initially starting the video.

mAppSdk.play(JSONObject channelInfo);

loadMetadata

Needs to be called at the beginning of each asset, pass JSON object for relevant content or ad. Make sure to pass as 1st loadMetadata for content at the begining of playlist - see below API call sequence examples.

mAppSdk.loadMetadata(JSONObject contentMetadata);

playheadPosition

Note: "setPlayheadPosition" has to be called every second and the value passed should match the broadcast time for live channel.
  • VOD: current position in seconds. Pass whole number that increments only by 1 like 0,1,2,3...
  • Live: Unix timestamp matching the broadcast time for Content and Ad (seconds since Jan-1-1970 UTC). Pass whole number that increments only by 1 like 1631098029,1631098030,1631098031,1631098032,...
mAppSdk.setPlayheadPosition(long videoPositon);

sendID3

Needs to be called when ID3 Tags are included in the Video Stream.

mAppSdk..sendID3(String id3);

ID3 Tags are parsed from the Video Stream, refer to the DK Reference Implementation sdkRefImplDK on how to parse ID3 Tags included in a sample HLS Stream. For further technical details, please contact your Technical Account Manager (TAM).

stop

Call when

  • ads complete playing
  • when a user pauses playback
  • upon any user interruption scenario - see bellow chapter Interruption scenario
mAppSdk.stop();

end

Call when the content asset completes playback. Stops measurement progress.

mAppSdk.end();



Start the Measurement

In order to start the measurement, follow the 3 first steps below for Content without Ads. When terminating the Content playback call end to terminate the Content Measurement for the given asset.

Playlist Sample code Description
1. Start of stream play(channelName) channelName contains JSON metadata of channel/video name being played
loadMetadata(contentMetadataObject) contentMetadataObject contains the JSON metadata for the content being played
2. Content is playing playheadPosition(position) playheadPosition is position of the playhead while the content is being played
sendID3(id3) id3 is an ID3 Tag parsed from the Video Stream, pass ID3 Tag immediately to SDK when found
3. End of Stream end Content playback is completed.

Step 5: Stop/Resume the Measurement for video Playback Interruptions

As part of integrating Nielsen App SDK with the player application, the Audio / Video app developer needs to handle the following possible interruption scenarios:

  • Pause / Play
  • Network Loss (Wi-Fi / Airplane / Cellular)
  • Call Interrupt (SIM or Third party Skype / Hangout call)
  • Alarm Interrupt
  • Content Buffering
  • Device Lock / Unlock (Video players only, not for Audio players)
  • App going in the Background/Foreground (Video players only, not for Audio players)
  • Channel / Station Change Scenario
  • Unplugging of headphone

In case of encountering one of the above interruptions, the player application needs to

  • Call stop immediately (except when content is buffering) and withhold sending playhead position.
  • Once the playback resumes, start sending pings playheadPosition for the new viewing session.

Please see the Digital Measurement FAQ for more details

Step 6: Review SDK Integration Architecture Diagram

For Content Playback

SDK Integration Architecture Diagram - Content

For Ad Playback

SDK Integration Architecture Diagram - Ad

Step 7 : Disclose Nielsen Privacy Statement

The App SDK uses Mobile Ad IDs (Android ID or IDFA) which are fully hashed on the device before being sent to Nielsen (Nielsen never receives un-hashed values). Users retain the possibility to oppose the use of Mobile Ad IDs, or to reset them, by using the functionality provided by the mobile operating system (iOS or Android).

In order to disclose Nielsen measurement privacy statement, please include the following items in your privacy policy:

Step 8 : Review the Reference Implementation for VoD and Live Streams

The Reference Implementation covers VoD and Live use cases. It also covers DAI (Dynamic Ad Insertion) with preroll Ad.

Download the Reference Implementation for Android DKRefPLAYER. Unzip and open the project in Android Studio, then run it i.e. in the simulator or on Android device and then filter the Logcat output with ">>>" in order to see only relevant Nielsen SDK API Calls, as below:

2021-04-08 15:11:27.075  D/NielsenInit: ====>>> SDK CALL : class NielsenInit :: Create new AppSdk() Instance.
2021-04-08 15:11:27.568  D/NielsenInit: ====>>> SDK EVENT - onAppSdkEvent: Description = Nielsen App SDK is initiated. AppSdk.jar aa.8.0.0.0_gsxaon. App SDK was successfully initiatedCode l param : 1617887487Code i param 2000
2021-04-08 15:11:29.497  D/NielsenInit: ====>>> SDK EVENT - onAppSdkEvent: Description = Nielsen App SDK has started up. AppSdk.jar aa.8.0.0.0_gsxaon. Config file successfully loaded and parsed.Code l param : 1617887489Code i param 2001
2021-04-08 15:11:42.736  D/MainActivity: ====>>> SDK CALL :  appSdk.play(sdkMethods.loadChannelInfo());
2021-04-08 15:11:42.738  D/MainActivity: ====>>> SDK CALL : onPrepared() : appSdk.loadMetadata(data)
2021-04-08 15:11:43.065  D/MainActivity: ====>>> Media Player Event : onInfo ();what = 3
2021-04-08 15:11:43.065  D/MainActivity: ====>>> Media Player Event :  first video frame pushed for rendering.
2021-04-08 15:11:43.747  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 0 / 224
2021-04-08 15:11:44.752  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 1 / 224
2021-04-08 15:11:45.759  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 2 / 224
2021-04-08 15:11:46.764  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 3 / 224
2021-04-08 15:11:47.767  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 4 / 224
2021-04-08 15:11:48.772  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 5 / 224
2021-04-08 15:11:49.777  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 6 / 224
2021-04-08 15:11:50.781  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 7 / 224
2021-04-08 15:11:51.819  D/MainActivity: ====>>> SDK CALL :   appSdk.setPlayheadPosition(mCurrentPosition): @ 8 / 224
2021-04-08 15:11:51.821  D/MainActivity: ====>>> Activity onPause()
2021-04-08 15:11:52.668  D/MainActivity: ====>>>: Activity onDestroy()
2021-04-08 15:11:52.668  D/MainActivity: ====>>> SDK CALL : terminateNielsenSDK () :appSdk.end();

Step 9 : Test your player by yourself

Guide

1. Connect your PC and test device (tablet or phone) via same router.
2. PC side: run Proxy sw (like Charles) and get local IP
3. Test device: modify Wifi setting to pass through Proxy IP from step 2.
4. Test device: run your player, launch video
5. PC side: filter traffic by "nmr" and confirm presence of GN pings

Example of GN ping

https://secure-dmk.nmrodam.com/cgi-bin/gn?prd=dcr&ci=us-500207&ch=us-500207_c77_P&asn=defChnAsset&fp_id=&fp_cr_tm=&fp_acc_tm=&fp_emm_tm=&ve_id=&devmodel=&manuf=&sysname=&sysversion=&sessionId=zlmmxkq867zt4bpnumlyz6dpn9hyp1610980356&tl=Episode%201&prv=1&c6=vc%2Cc77&ca=us-500207_c77_VID5556674-123456&cg=TAMSample%20DK&c13=asid%2CP10DF14BA-937E-436D-99DF-ED39A0422387&c32=segA%2CNA&c33=segB%2CNA&c34=segC%2CNA&c15=apn%2C&plugv=&playerv=&sup=1&segment2=&segment1=&forward=0&ad=0&cr=4_00_99_V1_00000&c9=devid%2C&enc=true&c1=nuid%2C999&at=view&rt=video&c16=sdkv%2Cbj.6.0.0&c27=cln%2C0&crs=&lat=&lon=&c29=plid%2C16109803568088038&c30=bldv%2C6.0.0.563&st=dcr&c7=osgrp%2C&c8=devgrp%2C&c10=plt%2C&c40=adbid%2C&c14=osver%2CNA&c26=dmap%2C1&dd=&hrd=&wkd=&c35=adrsid%2C&c36=cref1%2C&c37=cref2%2C&c11=agg%2C1&c12=apv%2C&c51=adl%2C0&c52=noad%2C0&sd=170&devtypid=&pc=NA&c53=fef%2Cy&c54=oad%2C20200713%2010%3A22%3A00&c55=cref3%2C&c57=adldf%2C2&ai=VID5556674-123456&c3=st%2Cc&c64=starttm%2C1610980392&adid=VID5556674-123456&c58=isLive%2Cfalse&c59=sesid%2Cgezrb92q4i9b9jg7acxgn783gjw0a1610980365&c61=createtm%2C1610980392&c63=pipMode%2C&c68=bndlid%2C&nodeTM=&logTM=&c73=phtype%2C&c74=dvcnm%2C&c76=adbsnid%2C&c77=adsuprt%2C2&uoo=&evdata=&c71=ottflg%2C0&c72=otttyp%2Cnone&c44=progen%2C&davty=0&si=http%3A%2F%2Fnielsenonlinesupport.com%2Fdk%2Findex.htm&c66=mediaurl%2Cassets%252FRTVOD_C3%252Fprog_index.m3u8&c62=sendTime%2C1610980392&rnd=714644

Step 10 : Provide your app for certification

Once ready please send your application to Nielsen local staff for certification.

Step 11 : Going Live

After the integration has been certified (but not prior that), disable debug logging by deleting {nol_devDebug: "DEBUG"} from initialization call - see Step 2.