Android SDK API Reference: Difference between revisions
From Engineering Client Portal
No edit summary |
No edit summary |
||
Line 5: | Line 5: | ||
*The player application can use this object to collect HLS timed metadata through a [[sendID3()]] call. | *The player application can use this object to collect HLS timed metadata through a [[sendID3()]] call. | ||
The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package. It inherits from the closeable interface and exposes the public APIs the client’s app will use. Below is the declaration of the <code>AppSdk</code> class: <code>public class AppSdk implements Closeable</code> | The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package. It inherits from the closeable interface and exposes the public APIs the client’s app will use. Below is the declaration of the <code>AppSdk</code> class: <code>public class AppSdk implements Closeable</code> | ||
== Setting Up Development Environment == | |||
'''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 Nielsen App SDK 1.2 library is composed of two parts: | |||
* The Java AppSdk.jar library that runs on the Android’s Dalvik Virtual Machine. | |||
* The C/C++ libAppSdk.so native library that runs directly on the device’s hardware. | |||
<blockquote>'''Note''': App SDK 4.0.0 contains AppSDK.jar component only and does not support C/C++ libAppSdk.so components.</blockquote | |||
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. | |||
* '''For Audio player applications''' | |||
** The Android OS hosting the App SDK should be at version 2.3 and later since the SDK depends on the Google Play support to work properly. | |||
=== Setting up in Eclipse IDE === | |||
Ensure to unzip the Nielsen App SDK sample app and copy the ''AppSdk.jar'' into the libs/ folder on the App’s Eclipse project. Copy the ''libAppSdk.so'' file under ''libs/armeabi/'' folder into the same Eclipse project. | |||
* App SDK 1.2 provides support for x86, mips, and armeabi-7a architecture; the respective ''libAppSdk.so'' can be found under the ''libs/x86/'', ''libs/mips/'', and ''libs/armeabi-7a/'' folders. | |||
Add the following permissions on the project’s ''AndroidManifest.xml'' file. | |||
<syntaxhighlight lang="java"><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:required="false" /> | |||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | |||
<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]. Download the latest ''google-play-services_lib'' and include it in the App’s project in order to use the App SDK. | |||
* 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. | |||
To include the Google Play library in the media player project, copy the ''google-play-services_lib'' folder into the same location as the project | |||
* Access '''File > Import'''. | |||
* Select '''Existing Android Code into Workspace''' and click '''Next'''. | |||
* Click '''Browse''' and navigate to the ''google-play-services_lib'' to include it into the projects. | |||
* Select the exact '''Project Build Target''' for Eclipse to use from Android SDK. | |||
** Android 4.4.2, etc. OR | |||
** Edit ''project.properties'' file to point to Android target version e.g. target= android-19. | |||
[[File:andr-properties-drm.jpg]] | |||
Once the google-play-services_lib is included into the App project, include the following code under the <code><application></code> node in the <code>AndroidManifest.xml</code>. | |||
<syntaxhighlight lang="java"><meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/></syntaxhighlight> | |||
Also, include the ''version.xml'' file that comes with the ''google-play-services_lib'' under the res/values directory of the media player project. | |||
* Once the files are in place, import com.nielsen.app.sdk to the java source code and start accessing the public interface. | |||
Nielsen App SDK uses the following packages/classes from the Google Play service. | |||
'''Library''': | |||
* google-play-services_lib | |||
'''Classes/package''': | |||
* 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; | |||
=== Setting up in Android Studio IDE === | |||
Launch '''Android Studio''' and select '''Import project (Eclipse ADT)'''. | |||
[[File:andr-setup-launch.jpg]] | |||
Browse for project destination directory and click '''Next'''. | |||
[[File:andr-import-project.jpg]] | |||
Go to '''File > Project Structure > App > Dependencies'''. | |||
[[File:andr-pro-structure.jpg]] | |||
Click '''+''' to add library dependency. | |||
Select '''play-services''' and click '''OK''' | |||
[[File:andr-choose-library.jpg]] | |||
For more information, refer to https://developer.android.com/google/play-services/setup.html | |||
== Initialization == | |||
NEED TO PORT OVER INITIALIZATION | |||
== Retrieving ID3 Tags == | |||
ID3 tags have a payload of about 249 characters and start with "www.nielsen.com". | |||
=== Sample ID3 tags === | |||
* <code>www.nielsen.com/X100zdCIGeIlgZnkYj6UvQ==/X100zdCIGeIlgZnkYj6UvQ==/AAAB2Jz2_k74GXSzx4npHuI_<wbr />JwJd3QSUpW30rDkGTcbHEzIMWleCzM-uvNOP9fzJcQMWQLJqzXMCAxParOb5sGijSV9dNM3QiBniJYGZ5GI-lL1fXTTN0IgZ4iWBmeRiPpS9AAAAAAAAAAAAAAAAAAAAAFJWFM5SVhTONNU=/00000/00000/00</code> | |||
* <code>www.nielsen.com/X100zdCIGeIlgZnkYj6UvQ==/R8WHe7pEBeqBhu8jTeXydg==/AAICoyitYqlxT7n6aZ0oMCGhe<wbr />Fi4CXFp46AMUPZz1lMr_M9tr3_cjee1SHqxrOiVerMDLeyn9xzocZSKwi746Re8vNOtpNCAZjYABs_J0R25IHpvOc1HS8<wbr />QHGgD5TgOJeS6gX100zdCIGeIlgZnkYj6UvVJWFNhSVhTiPE0=/00000/46016/00</code> | |||
<blockquote>'''Note''': ID3 tags are not applicable for International (Germany)</blockquote> | |||
=== Extracting ID3 tags from Android Players === | |||
==== ID3 Support Matrix ==== | |||
{| class="wikitable" | |||
|- | |||
! Player Name !! Minimum supported version !! Description | |||
|- | |||
| Android Native Media Player || Android 6 || Android 6 Media Player allows apps to register a callback to be invoked, when a selected track has the timed metadata available. Currently, only HTTP Live Streaming (HLS) data URI’s embedded with timed ID3 tags, generates TimedMetaData. | |||
|- | |||
| Google ExoPlayer || Android 4.1 || | |||
|- | |||
| Brightcove Player || Android 4.1 || Support for Android versions 2.3.3 and 4.0 is now deprecated. Learn more about why Brightcove is removing support for these versions as of January 1, 2016 in this [https://support.brightcove.com/en/perform/docs/announcement-brightcove-sdk-android-version-support|announcement] | |||
|- | |||
| Adobe PrimeTime Player || Android 4.2 || | |||
|- | |||
| VisualOn Player || Android 2.3 || Android 5 is the latest supported version | |||
|- | |||
| NexStream Player || Android 1.6 || Supported till Android 6 | |||
|} | |||
==== Android Native Media Player ==== | |||
As the Android Media Player versions (prior to Android 6 / Android API 23) do not support ID3, Nielsen has created a library that becomes an extension to the media player, thus MPX. This library extracts the ID3 tags and sends them to the app. For more information on how to use the MPX component, refer to the Nielsen-supplied sample application. | |||
Starting from '''Android 6 (Android API 23)''', Android Native Media Player allows apps to register a callback to be invoked, when a selected track has the timed metadata available. Currently, only HTTP Live Streaming (HLS) data URI’s embedded with timed ID3 tags generate TimedMetadata. Once the HLS video starts, call onTimedMetaDataAvailable() as and when the player observes a TimedMetadata (ID3 tag). | |||
<syntaxhighlight lang="java">@Override | |||
public void onTimedMetaDataAvailable(MediaPlayer mp, TimedMetaData data) | |||
{ | |||
byte[] iD3PayloadArray = data.getMetaData(); | |||
String iD3Payload = new String(iD3PayloadArray, StandardCharsets.UTF_8); | |||
if (null != iD3Payload && iD3Payload.contains("www.nielsen.com")) | |||
{ | |||
int index = iD3Payload.indexOf("www.nielsen.com"); | |||
String id3String = iD3Payload.substring(index, (index + 249)); | |||
Log.d(TAG, "TimedMetaData ID3 Tag:" + id3String); | |||
appProcessID3tag(id3String); | |||
} | |||
}</syntaxhighlight> | |||
==== ExoPlayer ==== | |||
he SDK is designed around an event-driven architecture where components emit events to allow other components to listen and respond to state changes. | |||
'''Player SDK Classes used:''' | |||
<syntaxhighlight lang="java">com.google.android.exoplayer.demo.player.DemoPlayer</syntaxhighlight> | |||
Since Nielsen App SDK is interested in extracting the Timed Metadata (ID3 Tags) in HLS and VOD on the EXO Player, trace the ID3_TAG emitted during video content played using EXOPlayer component as below. | |||
<syntaxhighlight lang="java">DemoPlayer implements ExoPlayer.Listener | |||
—————————————————– | |||
/** | |||
* A listener for receiving ID3 metadata parsed from the media stream. | |||
*/ | |||
public interface Id3MetadataListener | |||
{ | |||
void onId3Metadata(Map<String, Object> metadata); | |||
} | |||
——————————————————- | |||
MetadataTrackRenderer.MetadataRenderer<Map<String, | |||
Object>> getId3MetadataRenderer() | |||
{ | |||
return new MetadataTrackRenderer.MetadataRenderer<Map<String, Object>>() | |||
{ | |||
@Override | |||
public void onMetadata(Map<String, Object> metadata) | |||
{ | |||
if (id3MetadataListener != null) | |||
{ | |||
id3MetadataListener.onId3Metadata(metadata); | |||
} | |||
} | |||
}; | |||
}</syntaxhighlight> | |||
Also in ''Player.java'' class: | |||
<syntaxhighlight lang="java">Player implements DemoPlayer.Id3MetadataListener | |||
—————————————————– | |||
@SuppressWarnings("rawtypes") | |||
@Override | |||
public void onId3Metadata(Map<String, Object> metadata) | |||
{ | |||
try | |||
{ | |||
for (Object o : metadata.entrySet()) | |||
{ | |||
Map.Entry pairs = (Map.Entry) o; | |||
if (metadata.containsKey(TxxxMetadata.TYPE)) | |||
{ | |||
TxxxMetadata txxxMetadata = (TxxxMetadata) metadata | |||
.get(TxxxMetadata.TYPE); | |||
} | |||
else | |||
{ | |||
String aStr = new String((byte[]) pairs.getValue()); | |||
MainActivity.mAppSdk.sendID3(aStr); | |||
} | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
e.printStackTrace(); | |||
Log.d(TAG, "onId3Metadata(): No Id3 tags"); | |||
} | |||
}</syntaxhighlight> | |||
[[File:Andr-exo-retrievingID3tags.png|center|link=1]] | |||
==== Brightcove Player ==== | |||
While the Brightcove player plays the content, EventListener triggers an event when an ID3 packet is received (<code>SeamlessVideoDisplayComponent.ID3_TAG</code>). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis. | |||
<syntaxhighlight lang="java">brightcoveVideoView.getEventEmitter().on(SeamlessVideoDisplayComponent.ID3_TAG, new EventListener() | |||
{ | |||
public void processEvent(Event event) | |||
{ | |||
NlsId3Tag nlsID3 = new NlsId3Tag(event.properties.get(SeamlessVideoDisplayComponent.ID3_DATA).toString()); | |||
Log.w("ID3", nlsID3.NlsPayload); | |||
// Sent ID3 Tags to App | |||
appProcessID3tag(nlsID3.NlsPayload); | |||
} | |||
}); | |||
}</syntaxhighlight> | |||
==== Adobe PrimeTime Player ==== | |||
While the Adobe PrimeTime player plays the content, MediaPlayer.PlaybackEventListener triggers a callback when an ID3 packet is received (onTimedMetadata). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis. | |||
<syntaxhighlight lang="java">public void onTimedMetadata(TimedMetadata id3Metadata) | |||
{ | |||
NlsId3Tag nlsID3 = new NlsId3Tag(id3Metadata.getMetadata().toString()); | |||
Log.w(LOG_TAG, "ID3 Timed Data –> " + nlsID3.NlsPayload); | |||
Log.w(LOG_TAG, "PayLoad Size –> " + nlsID3.NlsPayload.length()); | |||
appProcessID3tag(nlsID3.NlsPayload); | |||
}</syntaxhighlight> | |||
==== VisualOn Player ==== | |||
While the VisualOn player plays the content, <code>VOCommonPlayerListener</code> triggers an event when an ID3 packet is received (<code>VO_OSMP_SRC_CUSTOMERTAGID_TIMEDTAG</code>). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis. | |||
<syntaxhighlight lang="java">case VO_OSMP_SRC_CB_CUSTOMER_TAG: | |||
{ | |||
VO_OSMP_SRC_CUSTOMERTAGID tag = VO_OSMP_SRC_CUSTOMERTAGID.valueOf(nParam1); | |||
switch (tag) | |||
{ | |||
case VO_OSMP_SRC_CUSTOMERTAGID_TIMEDTAG: | |||
// do something with this tag | |||
int time = nParam2; | |||
byte[] b = (byte[]) obj; | |||
String s = new String(b); | |||
NlsId3Tag nlsID3 = new NlsId3Tag(b); | |||
// Sent ID3 Tags to App | |||
appProcessID3tag(nlsID3.NlsPayload); | |||
if (appid3If != null) | |||
appid3If.onId3(nlsID3.NlsPayload); | |||
break; | |||
case VO_OSMP_SRC_CUSTOMERTAGID_MAX: | |||
// ignore this type of tag | |||
break; | |||
default: | |||
break; | |||
} | |||
break; | |||
}</syntaxhighlight> | |||
==== NextStream Player ==== | |||
ID3 tags will be received in the NexStream Player through <code>onTimedMetaRenderRender(NexPlayer mp,NexID3TagInformation metadata)</code> callback API. A sample implementation for the callback is shown below: | |||
<syntaxhighlight lang="java">public void onTimedMetaRenderRender(NexPlayer mp, NexID3TagInformation m) | |||
{ | |||
text = m.getPrivateFrame(); | |||
if (text != null) | |||
{ | |||
data = text.getTextData(); | |||
if (data != null) | |||
{ | |||
// make sure to identify the beginning of the | |||
// Nielsen ID3 tag payload by searching for the | |||
// "www.nielsen.com" string on the ID3 tag and | |||
// passing to the App SDK all information that | |||
// follows. It should be: | |||
// nlsPayload = "www.nielsen.com" + dataFollowing | |||
nlsPayload = getDataAfterWwwNielsenCom(data); | |||
if (nlsPayload!= NULL) | |||
mAppSdk.sendID3(nlsPayload); | |||
} | |||
} | |||
}</syntaxhighlight> | |||
The [[sendID3()]] sends the extracted Nielsen ID3 payload to the App SDK for analysis. | |||
== Android SDK API Methods & Properties == | == Android SDK API Methods & Properties == | ||
Line 57: | Line 326: | ||
|- | |- | ||
| Log || [[setDebug()]] || ✘ || ✘ || ✘ || ✘ || ✔ || Used to enable/disable debug flags. Newly introduced in SDK version 5.0.0 for International (Germany) | | Log || [[setDebug()]] || ✘ || ✘ || ✘ || ✘ || ✔ || Used to enable/disable debug flags. Newly introduced in SDK version 5.0.0 for International (Germany) | ||
|} | |||
== Android Opt-Out Implementation == | |||
== Nielsen Sample Applications == | |||
== Nielsen Privacy Requirements == | |||
Privacy protections that Nielsen ensures to have with each App SDK integration are as follows. | |||
*Disclosure of viewership data collection in app store description | |||
*Disclosure of viewership data collection in EULA / Privacy Policy | |||
*A link in the EULA/Privacy policy, or in another conspicuous location within the App, to a Nielsen-hosted web page outlining what Nielsen is collecting and how it is being used | |||
*Method for users to opt-out of Nielsen measurement, any time while using the application | |||
== Event and Error Handling == | |||
=== App SDK Error Codes === | |||
Constants with predefined error codes which the AppSdk object can generate. | |||
<syntaxhighlight lang="java">public static final int ERROR_FAILED_CREATE_URL_STRING = 1001; | |||
// failed generating ping string due to error on parsing | |||
// description – include last error message from URL parser | |||
public static final int ERROR_FAILED_RECEIVE_CONFIG = 1002; | |||
// failed to receive configuration file from Census | |||
// description – on 5th time, it will log event and keep requesting config 10 min apart | |||
public static final int ERROR_FAILED_PARSING_CONFIG = 1003; | |||
// failed parsing the config file JSON string | |||
// description – include json error number/short message from iOS or Android | |||
public static final int ERROR_FAILED_PARSING_PLAY = 1004; | |||
// failed parsing the play() JSON string | |||
// description – include json error number/short message from iOS or Android | |||
public static final int ERROR_FAILED_PARSING_METADATA = 1005; | |||
// failed parsing the play() JSON string | |||
// description – include JSON error number/short message from iOS or Android | |||
public static final int ERROR_FAILED_GENERATING_PING = 1006; | |||
// failed creating ping before adding it to the UPLOAD table) | |||
// description – include ping nol_url index, cadence to identify ping | |||
public static final int ERROR_FAILED_PROCESSOR_START = 1007; | |||
// failed starting data processor thread. Normally, that means a product | |||
// description – include processor that failed to start | |||
public static final int ERROR_FAILED_PROCESS_ID3 = 1008; | |||
// failed processing data on a data processor. Normally, that means the input to a product | |||
// description – include processor and data that failed to process (ID3 tag on a MTVR impression, for example) | |||
public static final int ERROR_FAILED_HTTP_SEND = 1009; | |||
// failed sending HTTP or HTTPS requests | |||
// description – include HTTP error number | |||
public static final int ERROR_FAILED_SENDING_PING = 1010; | |||
// failed sending pings (on ANDROID, the ping on the UPLOAD table) | |||
// description – include ping up to 80 char from the end | |||
public static final int ERROR_FAILED_SENDING_TSV = 1011; | |||
// failed sending TSV requests | |||
// description – include TSV request message | |||
public static final int ERROR_FAILED_SENDING_STATION_ID = 1012; | |||
// failed sending StationId requests | |||
// description – include Station ID request message | |||
public static final int ERROR_FAILED_ACCESSING_DB = 1013; | |||
// failed read/write from/to database table | |||
// description – include SQL statement and data and SQLite error number/message | |||
public static final int ERROR_CHANGED_DEVICE_ID = 1014; | |||
// device ID changed | |||
// description – none | |||
public static final int ERROR_CHANGED_NUID = 1015; | |||
// NUID changed | |||
// description – none | |||
public static final int ERROR_SDK_NOT_INITIALIZED = 1016; | |||
// App SDK initialization failed | |||
// description – none | |||
public static final int ERROR_FAILED_SDK_SUSPEND = 1017; | |||
// App SDK failed to suspend activities | |||
// description – none | |||
public static final int ERROR_INVALID_PARAMETERS = 1018; | |||
// App SDK invalid parameters | |||
// description – none | |||
public static final int ERROR_INVALID_STATE = 1019; | |||
// App SDK called in incorrect state | |||
// description – none | |||
public static final int ERROR_FAILED_PROCESS_PLAYHEAD = 1020; | |||
// App SDK failed processing playhead position | |||
// description – none | |||
public static final int ERROR_FAILED_PROCESS_METADATA = 1021; | |||
// App SDK failed processing not-null, syntax valid JSON metadada | |||
// description – none | |||
public static final int ERROR_FAILED_PROCESS_STOP = 1022; | |||
// App SDK failed processing stop | |||
// description – none</syntaxhighlight> | |||
=== App SDK Event Codes === | |||
<syntaxhighlight lang="java">public static final int EVENT_INITIATE = 2000; | |||
// App SDK is initiated. It will happen as soon as the App SDK is initialized | |||
public static final int EVENT_STARTUP = 2001; | |||
// App SDK has started up. It will happen only after App SDK has received a valid config file. This is the location in the code to acquire the value of userOptOutURLString(). | |||
public static final int EVENT_SHUTDOWN = 2002; | |||
// App SDK is shutting down. It will happen just before App SDK is destroyed</syntaxhighlight> | |||
'''App SDK Event Codes ''' | |||
{| class="wikitable" | |||
|- | |||
! Event Code !! Event Name !! Event Description | |||
|- | |||
| 2000 || EVENT_INITIATE || App SDK is initiated. It will happen as soon as the App SDK is initialized | |||
|- | |||
| 2001 || EVENT_STARTUP || App SDK has started up. It will happen only after App SDK has received a valid config file | |||
|- | |||
| 2002 || EVENT_SHUTDOWN || App SDK is shutting down. It will happen just before App SDK is destroyed | |||
|} | |} |
Revision as of 21:42, 24 May 2017
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.
- Create and initialize an instance object of
AppSdk
class. - The player application can use this object to collect HLS timed metadata through a sendID3() call.
The Nielsen App SDK class is defined as the only public class belonging to the com.nielsen.app.sdk package. It inherits from the closeable interface and exposes the public APIs the client’s app will use. Below is the declaration of the AppSdk
class: public class AppSdk implements Closeable
Setting Up Development Environment
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 Nielsen App SDK 1.2 library is composed of two parts:
- The Java AppSdk.jar library that runs on the Android’s Dalvik Virtual Machine.
- The C/C++ libAppSdk.so native library that runs directly on the device’s hardware.
Note: App SDK 4.0.0 contains AppSDK.jar component only and does not support C/C++ libAppSdk.so components.
Import.
- Select Existing Android Code into Workspace and click Next.
- Click Browse and navigate to the google-play-services_lib to include it into the projects.
- Select the exact Project Build Target for Eclipse to use from Android SDK.
- Android 4.4.2, etc. OR
- Edit project.properties file to point to Android target version e.g. target= android-19.
Once the google-play-services_lib is included into the App project, include the following code under the <application>
node in the AndroidManifest.xml
.
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
Also, include the version.xml file that comes with the google-play-services_lib under the res/values directory of the media player project.
- Once the files are in place, import com.nielsen.app.sdk to the java source code and start accessing the public interface.
Nielsen App SDK uses the following packages/classes from the Google Play service.
Library:
- google-play-services_lib
Classes/package:
- 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;
Setting up in Android Studio IDE
Launch Android Studio and select Import project (Eclipse ADT).
Browse for project destination directory and click Next.
Go to File > Project Structure > App > Dependencies.
Click + to add library dependency.
Select play-services and click OK
For more information, refer to https://developer.android.com/google/play-services/setup.html
Initialization
NEED TO PORT OVER INITIALIZATION
Retrieving ID3 Tags
ID3 tags have a payload of about 249 characters and start with "www.nielsen.com".
Sample ID3 tags
www.nielsen.com/X100zdCIGeIlgZnkYj6UvQ==/X100zdCIGeIlgZnkYj6UvQ==/AAAB2Jz2_k74GXSzx4npHuI_
JwJd3QSUpW30rDkGTcbHEzIMWleCzM-uvNOP9fzJcQMWQLJqzXMCAxParOb5sGijSV9dNM3QiBniJYGZ5GI-lL1fXTTN0IgZ4iWBmeRiPpS9AAAAAAAAAAAAAAAAAAAAAFJWFM5SVhTONNU=/00000/00000/00 www.nielsen.com/X100zdCIGeIlgZnkYj6UvQ==/R8WHe7pEBeqBhu8jTeXydg==/AAICoyitYqlxT7n6aZ0oMCGhe
Fi4CXFp46AMUPZz1lMr_M9tr3_cjee1SHqxrOiVerMDLeyn9xzocZSKwi746Re8vNOtpNCAZjYABs_J0R25IHpvOc1HS8 QHGgD5TgOJeS6gX100zdCIGeIlgZnkYj6UvVJWFNhSVhTiPE0=/00000/46016/00
Note: ID3 tags are not applicable for International (Germany)
Extracting ID3 tags from Android Players
ID3 Support Matrix
Player Name | Minimum supported version | Description |
---|---|---|
Android Native Media Player | Android 6 | Android 6 Media Player allows apps to register a callback to be invoked, when a selected track has the timed metadata available. Currently, only HTTP Live Streaming (HLS) data URI’s embedded with timed ID3 tags, generates TimedMetaData. |
Google ExoPlayer | Android 4.1 | |
Brightcove Player | Android 4.1 | announcement] |
Adobe PrimeTime Player | Android 4.2 | |
VisualOn Player | Android 2.3 | Android 5 is the latest supported version |
NexStream Player | Android 1.6 | Supported till Android 6 |
Android Native Media Player
As the Android Media Player versions (prior to Android 6 / Android API 23) do not support ID3, Nielsen has created a library that becomes an extension to the media player, thus MPX. This library extracts the ID3 tags and sends them to the app. For more information on how to use the MPX component, refer to the Nielsen-supplied sample application.
Starting from Android 6 (Android API 23), Android Native Media Player allows apps to register a callback to be invoked, when a selected track has the timed metadata available. Currently, only HTTP Live Streaming (HLS) data URI’s embedded with timed ID3 tags generate TimedMetadata. Once the HLS video starts, call onTimedMetaDataAvailable() as and when the player observes a TimedMetadata (ID3 tag).
@Override
public void onTimedMetaDataAvailable(MediaPlayer mp, TimedMetaData data)
{
byte[] iD3PayloadArray = data.getMetaData();
String iD3Payload = new String(iD3PayloadArray, StandardCharsets.UTF_8);
if (null != iD3Payload && iD3Payload.contains("www.nielsen.com"))
{
int index = iD3Payload.indexOf("www.nielsen.com");
String id3String = iD3Payload.substring(index, (index + 249));
Log.d(TAG, "TimedMetaData ID3 Tag:" + id3String);
appProcessID3tag(id3String);
}
}
ExoPlayer
he SDK is designed around an event-driven architecture where components emit events to allow other components to listen and respond to state changes.
Player SDK Classes used:
com.google.android.exoplayer.demo.player.DemoPlayer
Since Nielsen App SDK is interested in extracting the Timed Metadata (ID3 Tags) in HLS and VOD on the EXO Player, trace the ID3_TAG emitted during video content played using EXOPlayer component as below.
DemoPlayer implements ExoPlayer.Listener
—————————————————–
/**
* A listener for receiving ID3 metadata parsed from the media stream.
*/
public interface Id3MetadataListener
{
void onId3Metadata(Map<String, Object> metadata);
}
——————————————————-
MetadataTrackRenderer.MetadataRenderer<Map<String,
Object>> getId3MetadataRenderer()
{
return new MetadataTrackRenderer.MetadataRenderer<Map<String, Object>>()
{
@Override
public void onMetadata(Map<String, Object> metadata)
{
if (id3MetadataListener != null)
{
id3MetadataListener.onId3Metadata(metadata);
}
}
};
}
Also in Player.java class:
Player implements DemoPlayer.Id3MetadataListener
—————————————————–
@SuppressWarnings("rawtypes")
@Override
public void onId3Metadata(Map<String, Object> metadata)
{
try
{
for (Object o : metadata.entrySet())
{
Map.Entry pairs = (Map.Entry) o;
if (metadata.containsKey(TxxxMetadata.TYPE))
{
TxxxMetadata txxxMetadata = (TxxxMetadata) metadata
.get(TxxxMetadata.TYPE);
}
else
{
String aStr = new String((byte[]) pairs.getValue());
MainActivity.mAppSdk.sendID3(aStr);
}
}
}
catch (Exception e)
{
e.printStackTrace();
Log.d(TAG, "onId3Metadata(): No Id3 tags");
}
}
Brightcove Player
While the Brightcove player plays the content, EventListener triggers an event when an ID3 packet is received (SeamlessVideoDisplayComponent.ID3_TAG
). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis.
brightcoveVideoView.getEventEmitter().on(SeamlessVideoDisplayComponent.ID3_TAG, new EventListener()
{
public void processEvent(Event event)
{
NlsId3Tag nlsID3 = new NlsId3Tag(event.properties.get(SeamlessVideoDisplayComponent.ID3_DATA).toString());
Log.w("ID3", nlsID3.NlsPayload);
// Sent ID3 Tags to App
appProcessID3tag(nlsID3.NlsPayload);
}
});
}
Adobe PrimeTime Player
While the Adobe PrimeTime player plays the content, MediaPlayer.PlaybackEventListener triggers a callback when an ID3 packet is received (onTimedMetadata). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis.
public void onTimedMetadata(TimedMetadata id3Metadata)
{
NlsId3Tag nlsID3 = new NlsId3Tag(id3Metadata.getMetadata().toString());
Log.w(LOG_TAG, "ID3 Timed Data –> " + nlsID3.NlsPayload);
Log.w(LOG_TAG, "PayLoad Size –> " + nlsID3.NlsPayload.length());
appProcessID3tag(nlsID3.NlsPayload);
}
VisualOn Player
While the VisualOn player plays the content, VOCommonPlayerListener
triggers an event when an ID3 packet is received (VO_OSMP_SRC_CUSTOMERTAGID_TIMEDTAG
). Upon receiving this event, collect the incoming ID3 tags and only pass the Nielsen payload of the PRIV frame to the App SDK for analysis.
case VO_OSMP_SRC_CB_CUSTOMER_TAG:
{
VO_OSMP_SRC_CUSTOMERTAGID tag = VO_OSMP_SRC_CUSTOMERTAGID.valueOf(nParam1);
switch (tag)
{
case VO_OSMP_SRC_CUSTOMERTAGID_TIMEDTAG:
// do something with this tag
int time = nParam2;
byte[] b = (byte[]) obj;
String s = new String(b);
NlsId3Tag nlsID3 = new NlsId3Tag(b);
// Sent ID3 Tags to App
appProcessID3tag(nlsID3.NlsPayload);
if (appid3If != null)
appid3If.onId3(nlsID3.NlsPayload);
break;
case VO_OSMP_SRC_CUSTOMERTAGID_MAX:
// ignore this type of tag
break;
default:
break;
}
break;
}
NextStream Player
ID3 tags will be received in the NexStream Player through onTimedMetaRenderRender(NexPlayer mp,NexID3TagInformation metadata)
callback API. A sample implementation for the callback is shown below:
public void onTimedMetaRenderRender(NexPlayer mp, NexID3TagInformation m)
{
text = m.getPrivateFrame();
if (text != null)
{
data = text.getTextData();
if (data != null)
{
// make sure to identify the beginning of the
// Nielsen ID3 tag payload by searching for the
// "www.nielsen.com" string on the ID3 tag and
// passing to the App SDK all information that
// follows. It should be:
// nlsPayload = "www.nielsen.com" + dataFollowing
nlsPayload = getDataAfterWwwNielsenCom(data);
if (nlsPayload!= NULL)
mAppSdk.sendID3(nlsPayload);
}
}
}
The sendID3() sends the extracted Nielsen ID3 payload to the App SDK for analysis.
Android SDK API Methods & Properties
Scenario | Method / Property | DTVR | DAR | Digital Audio | DCR | International (Germany) | Description |
---|---|---|---|---|---|---|---|
Initialize | AppSDK() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to create a new instance of the SDK object |
Measurement | play() | ✔ | ✔ | ✔ | ✔ | ✔ | Used when there is an ID3 fed product such as DTVR and the client does not want to send in all the CMS metadata that is sent in loadMetadata. This allows the client to send in at least the required “channel name” value associated to the ID3 feed. If this is not called then the “channel name” value populated will be the default value of “defaultChannelName”. |
Measurement | loadMetadata() | ✔ | ✔ | ✔ | ✔ | ✔ | Used when there is a preroll ad that needs to be associated with content metadata. The loadmetadata will first be called to populate the content metadata values and then the loadMetadata for ad metadata will be called. This allows sending a content ping with the ad info, even if the user bails out during the preroll ad. |
Measurement | sendID3() | ✔ | ✘ | ✘ | ✘ | ✘ | Used to send the ID3 metadata. |
Measurement | setPlayheadPosition() | ✘ | ✘ | ✔ | ✔ | ✔ | Used to send the playhead position. |
Measurement | stop() | ✔ | ✘ | ✔ | ✔ | ✔ | Used when playback is paused and when switching between ad and content or content and ad. |
Measurement | end() | ✔ | ✘ | ✔ | ✔ | ✔ | Used when content playback is complete. This is triggered 1) at the end of the content stream, 2) if the user switches to another piece of content |
Measurement | updateOTT() | ✘ | ✘ | ✘ | ✘ | ✔ | Used to notify App SDK that the remote OTT device (like Google ChromeCast, Roku, Amazon FireTV, etc.) is connected / disconnected (change of OTT status). |
Opt-out | userOptOutURLString() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to fetch the Nielsen opt-out web page URL. |
Opt-out | userOptOut() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to supply the response message from opt-out webpage to the SDK. |
Opt-out | getOptOutStatus() | ✘ | ✘ | ✘ | ✘ | ✔ | Call this API to retrieve the Opt-Out or Opt-In state. |
Opt-out | appDisableApi()
(kill switch) |
✔ | ✔ | ✔ | ✔ | ✔ | Used to disable the SDK. |
Opt-out | getAppDisable() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to query if the SDK is disabled or not. |
Log | getLastEvent() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to query the SDK for the last status |
Log | getLastError() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to query the SDK for the last error |
Log | isValid() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to check if the SDK was successfully instantiated or not. |
Log | getMeterVersion() | ✘ | ✘ | ✘ | ✘ | ✔ | Returns the current SDK version. |
Log | getNielsenId() | ✔ | ✔ | ✔ | ✔ | ✔ | Used to get a string defining the Nielsen ID (NUID) number for the device. |
Log | getDeviceId() | ✔ | ✔ | ✔ | ✔ | ✔ | Returns the current device id. |
Log | appInBackground() | ✘ | ✘ | ✘ | ✔ | ✔ | Used to capture the event of app going to background. |
Log | appInForeground() | ✘ | ✘ | ✘ | ✔ | ✔ | Used to capture the event of app coming to foreground |
Log | setDebug() | ✘ | ✘ | ✘ | ✘ | ✔ | Used to enable/disable debug flags. Newly introduced in SDK version 5.0.0 for International (Germany) |
Android Opt-Out Implementation
Nielsen Sample Applications
Nielsen Privacy Requirements
Privacy protections that Nielsen ensures to have with each App SDK integration are as follows.
- Disclosure of viewership data collection in app store description
- Disclosure of viewership data collection in EULA / Privacy Policy
- A link in the EULA/Privacy policy, or in another conspicuous location within the App, to a Nielsen-hosted web page outlining what Nielsen is collecting and how it is being used
- Method for users to opt-out of Nielsen measurement, any time while using the application
Event and Error Handling
App SDK Error Codes
Constants with predefined error codes which the AppSdk object can generate.
public static final int ERROR_FAILED_CREATE_URL_STRING = 1001;
// failed generating ping string due to error on parsing
// description – include last error message from URL parser
public static final int ERROR_FAILED_RECEIVE_CONFIG = 1002;
// failed to receive configuration file from Census
// description – on 5th time, it will log event and keep requesting config 10 min apart
public static final int ERROR_FAILED_PARSING_CONFIG = 1003;
// failed parsing the config file JSON string
// description – include json error number/short message from iOS or Android
public static final int ERROR_FAILED_PARSING_PLAY = 1004;
// failed parsing the play() JSON string
// description – include json error number/short message from iOS or Android
public static final int ERROR_FAILED_PARSING_METADATA = 1005;
// failed parsing the play() JSON string
// description – include JSON error number/short message from iOS or Android
public static final int ERROR_FAILED_GENERATING_PING = 1006;
// failed creating ping before adding it to the UPLOAD table)
// description – include ping nol_url index, cadence to identify ping
public static final int ERROR_FAILED_PROCESSOR_START = 1007;
// failed starting data processor thread. Normally, that means a product
// description – include processor that failed to start
public static final int ERROR_FAILED_PROCESS_ID3 = 1008;
// failed processing data on a data processor. Normally, that means the input to a product
// description – include processor and data that failed to process (ID3 tag on a MTVR impression, for example)
public static final int ERROR_FAILED_HTTP_SEND = 1009;
// failed sending HTTP or HTTPS requests
// description – include HTTP error number
public static final int ERROR_FAILED_SENDING_PING = 1010;
// failed sending pings (on ANDROID, the ping on the UPLOAD table)
// description – include ping up to 80 char from the end
public static final int ERROR_FAILED_SENDING_TSV = 1011;
// failed sending TSV requests
// description – include TSV request message
public static final int ERROR_FAILED_SENDING_STATION_ID = 1012;
// failed sending StationId requests
// description – include Station ID request message
public static final int ERROR_FAILED_ACCESSING_DB = 1013;
// failed read/write from/to database table
// description – include SQL statement and data and SQLite error number/message
public static final int ERROR_CHANGED_DEVICE_ID = 1014;
// device ID changed
// description – none
public static final int ERROR_CHANGED_NUID = 1015;
// NUID changed
// description – none
public static final int ERROR_SDK_NOT_INITIALIZED = 1016;
// App SDK initialization failed
// description – none
public static final int ERROR_FAILED_SDK_SUSPEND = 1017;
// App SDK failed to suspend activities
// description – none
public static final int ERROR_INVALID_PARAMETERS = 1018;
// App SDK invalid parameters
// description – none
public static final int ERROR_INVALID_STATE = 1019;
// App SDK called in incorrect state
// description – none
public static final int ERROR_FAILED_PROCESS_PLAYHEAD = 1020;
// App SDK failed processing playhead position
// description – none
public static final int ERROR_FAILED_PROCESS_METADATA = 1021;
// App SDK failed processing not-null, syntax valid JSON metadada
// description – none
public static final int ERROR_FAILED_PROCESS_STOP = 1022;
// App SDK failed processing stop
// description – none
App SDK Event Codes
public static final int EVENT_INITIATE = 2000;
// App SDK is initiated. It will happen as soon as the App SDK is initialized
public static final int EVENT_STARTUP = 2001;
// App SDK has started up. It will happen only after App SDK has received a valid config file. This is the location in the code to acquire the value of userOptOutURLString().
public static final int EVENT_SHUTDOWN = 2002;
// App SDK is shutting down. It will happen just before App SDK is destroyed
App SDK Event Codes
Event Code | Event Name | Event Description |
---|---|---|
2000 | EVENT_INITIATE | App SDK is initiated. It will happen as soon as the App SDK is initialized |
2001 | EVENT_STARTUP | App SDK has started up. It will happen only after App SDK has received a valid config file |
2002 | EVENT_SHUTDOWN | App SDK is shutting down. It will happen just before App SDK is destroyed |