Using the PolyNet™ SDK
This document is for PolyNetSDK version 3 for Android.
Imports
You will need to import classes from com.system73.polynet.android.sdk
and com.system73.polynet.android.sdk.core.metrics
packages.
The following classes are required:
import com.system73.polynet.android.sdk.PolyNet;
import com.system73.polynet.android.sdk.PolyNetConfiguration;
import com.system73.polynet.android.sdk.PolyNetListener;
import com.system73.polynet.android.sdk.core.metrics.PolyNetMetrics;
import com.system73.polynet.android.sdk.core.metrics.PolyNetOutboundMetrics;
import com.system73.polynet.android.sdk.exception.PolyNetException;
Connecting
The following parameters are needed for a successful integration with PolyNet SDK:
Name | Type | Description |
---|---|---|
manifestUrl | Mandatory | The amount of data as payload received from the CDN since the session started. (Kilobits). |
apiKey | Mandatory | Api Key provided by System73. Contact us in order to obtain it. |
context | Mandatory | Android Context of the Activity where the video player is shown. |
channelId | Optional | Custom identifier for the channel. |
playerBufferSize | Optional | The video player's buffer size in seconds, if you know it or can get it from the player. |
Initialize an instance of PolyNet object and uses the property localManifestUrl
to initialize the player.
try {
PolyNetConfiguration configuration = PolyNetConfiguration.builder()
.setManifestUrl(manifestUrl)
.setChannelId(channelId)
.setApiKey(apiKey)
.setBufferSize(playerBufferSize)
.setContext(context)
.build();
PolyNet polyNet = new PolyNet(configuration);
polyNet.setListener(polyNetListener);
// Init the player with the local manifest URL.
//
// For example:
// initializePlayer(polyNet.getLocalManifestUrl())
} catch {
// The PolyNet CANNOT be used as there was an initialisation issue.
// Init the player with the original manifest URL.
//
// For example:
// initializePlayer(manifesUrl)
// Where manifestUrl is the original URL of the manifest.
}
Important: Initialise the player instance with the localManifestUrl
property of the PolyNet instance. Do not start the player with the original manifest URL unless the PolyNet object fails to init.
If any required parameter is missing, invalid, or there are other problems during initialization, an exception of class PolyNetException
might be thrown.
You should catch it, examine the error message, and check your integration.
If problem persists, contact support at support@system73.com.
List of initialization errors
This is the list of the possible initialization errors that may be thrown. You can obtain the error code with the getCode()
method of class PolyNetException
.
Code | Description |
---|---|
-600 | Check your API Key. If problem persists, contact support at support@system73.com. |
-601 | Check your API Key. If problem persists, contact support at support@system73.com. |
-602 | Check your API Key. Detail: (...). If problem persists, contact support at support@system73.com. |
-603 | The PolyNet SDK has failed to build. Detail: (...). If problem persists, contact support at support@system73.com. |
Providing metrics
You MUST provide the PolyNet instance with some of the video player's metrics. For each reported metric, call the specific report methods of the PolyNet instance as explained below.
For PolyNet to work properly you MUST regularly provide the buffer health metric.
Each video player provides access to the metrics in different ways.
-
Some players periodically notify the subscribed listeners.
-
Some player's metrics may be obtained at any time.
The PolyNet instance supports both ways:
- You are free to report a metric at the moment it is reported by the player.
For example, ExoPlayer requires you to implement the
InfoListener
interface, and it will call itsonDroppedFrames
andonStateChanged
callbacks, as in the following code snippet. You should setup ExoPlayer to immediately report every single frame dropped.
// ... rest of code
player.addListener(new PlayerEventAdapter() {
@Override
public void onPlayerStateChanged(boolean playWhenReady, int state) {
if (state == Player.STATE_READY) {
if (polyNet != null) {
polyNet.reportPlayBackStarted();
}
}
}
});
// ... rest of code
player.setVideoDebugListener(new VideoRendererEventAdapter() {
@Override
public void onDroppedFrames(int count, long elapsed) {
for (int n = 0; n < count; n++) {
if (polyNet != null) {
polyNet.reportDroppedFrame();
}
}
}
});
// ... rest of code
In our Sample App using ExoPlayer 2, this source code is inside the PlayerActivity
class.
-
The PolyNet instance requests each metric asynchronously using the
PolyNetListener
instance assigned in the initialization steps. The metric can be reported directly from the callback, or when it is possible to fetch it from the player's instance. -
If it is not possible to get a metric from the player, don't call the specific report methods for that metric. In case that buffer health is not provided, the following WARNING message will be displayed in console log five times at most:
Buffer health not provided. This might cause QoE issues.
In the following example, you can see that the buffer health can be obtained from the player, but the other metrics are not available:
private final PolyNetListener polyNetListener = new PolyNetListener() {
@Override
public void onBufferHealthRequest(PolyNet polyNet) {
if (player != null) {
// Report the buffer health only if we can compute it
long bufferPos = player.getBufferedPosition();
long currentPos = player.getCurrentPosition();
long bufferHealthInMs = bufferPos - currentPos;
polyNet.reportBufferHealth(bufferHealthInMs);
}
}
@Override
public void onDroppedFramesRequest(PolyNet polyNet) {
// No need to implement it for ExoPlayer.
}
@Override
public void onPlayBackStartedRequest(PolyNet polyNet) {
// No need to implement it for ExoPlayer.
}
// ... rest of code
};
This source code is shown in the PlayerActivity
class of the System73 Sample App using ExoPlayer 2.
Handling events [Optional]
Error event
When the SDK finds a run-time problem (such as the Internet could not be accessed, etc.),
a corresponding PolyNetException
can be obtained from the onError()
method inside the polyNetListener
.
Nevertheless, the SDK will keep working as reliably as possible. This method is useful in the debugging of the integration process.
For example in our Sample App using ExoPlayer 2, this source code is added in the PlayerActivity
class.
private final PolyNetListener polyNetListener = new PolyNetListener() {
// ... rest of code
public void onError(PolyNet polyNet, PolyNetException e) {
Log.e(TAG, "PolyNet error", e);
}
// ... rest of code
};
You should print it to the logs, examine the error message, and check your integration. If problem persists, contact support at support@system73.com.
List of run-time errors
This is the list of the possible run-time errors that may be thrown. You can obtain the error code with the getCode()
method of class PolyNetException
.
Code | Description |
---|---|
-700 | The PolyNet SDK has failed and raised an exception. Detail: (...). If problem persists, contact support at support@system73.com. |
-701 | The PolyNet SDK is not compatible with the backend provided. Backend code: (...). This may happen in transitions to newer versions. If problem persists, contact support at support@system73.com. |
-702 | Error communicating with backend. Detail: (...). If problem persists, contact support at support@system73.com. |
-703 | Error communicating with backend metrics endpoint. Detail: (...). If problem persists, contact support at support@system73.com. |
Metrics event
You can get some of PolyNet metrics from the onMetrics
method inside the polyNetListener
. For each reported metric, call the specific get
method of the PolyNetMetrics instance:
private final PolyNetListener polyNetListener = new PolyNetListener() {
// ... rest of code
@Override
public void onMetrics(PolyNetMetrics polyNetMetrics) {
// Access metrics
}
// ... rest of code
};
The reported metrics are as following:
Name | Type | Description |
---|---|---|
accumulatedCdnDownThroughput | String | The amount of data as payload received from the CDN since the session started. (Kilobits). |
accumulatedP2pDownThroughput | String | The amount of data as payload received from P2P since the session started. (Kilobits). |
bufferFillingRate | String | The rate at which the content is received versus playing time. |
cdnDownThroughput | String | The amount of data as payload received from the CDN during the last reporting period. (Kilobits). |
connectionStatus | String | Describes the current connection status of the node. |
date | String | The timestamp on which the metrics object was created. |
deviceId | String | Unique identifier for the device running the PolyNet. |
inboundNodeId | String | Unique identifier for the inbound connection if connected to other peer or the value “POI” if downloading from CDN. |
nodeId | String | Unique identifier for the PolyNet node. |
outboundMetrics | Array | Metrics for outbound peers. See below Outbound Metrics. |
p2pDownThroughput | String | The amount of data as payload received from P2P during the last reporting period. (Kilobits). |
playerBufferHealth | String | The amount of milliseconds (playback time) that are left for playing in the player's video read-ahead buffer. |
playerTimeToFirstFrame | String | The amount of milliseconds from the start of the PolyNet until the player starts playback. |
primaryManifestUrl | String | HLS: This is the master playlist URL with .m3u or .m3u8 extensions. DASH: This is the manifest URL with .mpd extension. |
representationId | String | Unique identifier for the current representation or rendition being displayed. |
roundTripTime | String | The amount of time between sending a data packet from a child node to its inbound P2P peer and back. (milliseconds). |
secondaryManifestUrl | String | HLS: This is the media playlist URL with .m3u or .m3u8 extensions. |
source | String | The source specifies where the content is downloaded from. |
streamId | String | Unique identifier for the current stream being displayed. |
Outbound metrics:
Name | Type | Description |
---|---|---|
bufferFillingRate | String | The rate at which the content is received in the PolyNet outbound peer versus playing time. |
nodeId | String | Unique identifier for the PolyNet outbound peer. |
status | String | The status of the connection for the PolyNet outbound peer. |
Disconnecting from PolyNet
Listeners can be unsubscribed from the PolyNet instance as follows:
polyNet.removeListener();
To disconnect:
polyNet.dispose();
IMPORTANT: Once you dispose of this PolyNet instance, you MAY NOT use it again. If you want to connect to a new channel or the same channel, go back to the initialization steps and create a new instance.
Other considerations [Optional]
Streams with encryption keys
The optional property manageEncryptionKeys
can be used to initialize the PolyNet
instance. You may call the corresponding manageEncryptionKeys
method in the
PolyNetConfiguration.Builder
to set or unset it:
PolyNetConfiguration configuration = PolyNetConfiguration.builder()
.setManifestUrl(manifestUrl)
.setChannelId(channelId)
// ... rest of code
.manageEncryptionKeys(false) // true by default
.build();
PolyNet polyNet = new PolyNet(configuration);
// ... rest of code
Setting or unsetting this property is relevant on some scenarios where the stream is encrypted:
when the media segments need to be decrypted, the player usually needs to retrieve specific Key files.
With the manageEncryptionKeys
property you can choose whether these Key files are handled by the PolyNet SDK (true
) or by the player (false
).
This is relevant depending on the authentication scheme required to access the license servers and Key files.
When this property is set to false
, the PolyNet SDK delegates to the player all requests related to Key files.
This is useful when authentication is managed with cookies that need to be handled externally or prior the player is initialized.
This property is set to true
by default on the PolyNetConfiguration
.
Sharing content
The optional property sharingContent
controls whether the PolyNet shares the video content with other peers. This property is used after initializing the PolyNet
instance.
Accepts values from the SharingContent
enum which are the following:
Option | Description |
---|---|
NEVER | The video content will never be shared with other peers. |
ONLY_ON_LAN | The video content will be shared only if connected via WIFI or ETHERNET. |
ALWAYS | The video content will be shared with other peers whenever possible. |
This property is set to ONLY_ON_LAN
by default.
You will need to import the following class from com.system73.polynet.android.sdk
package.
import com.system73.polynet.android.sdk.SharingContent;
After this, you may call the corresponding sharingContent
method to set or unset it. For example:
PolyNet polyNet = new PolyNet(configuration);
// ... rest of code
polyNet.sharingContent(SharingContent.ONLY_ON_LAN);
Using cookies containing authentication tokens
Some content providers implement authentication with cookies containing the access tokens. Properly handling those cookies is necessary to grant access to the content.
To support content streams with cookies, the PolyNet instance needs access to an Android
CookieHandler
. Video players (like ExoPlayer) should be able to access one, in order
to properly handle cookies themselves. You should share the same CookieHandler
instance between the video player and the PolyNet SDK instance. If you don't explicitly
provide the SDK with a CookieHandler
, it will try to access the system-wide default
CookieHandler
instead.
The method to set the cookie handler is setCookieHandler
in PolyNetConfiguration.Builder
.