iOS SDK¶
This document applies to our SDK version 5.1.7 for iOS and tvOS. Its sample code is written in Swift 5.10
Requirements¶
iOS 12.0 or later, tvOS 12.0 or later, and the Latest Xcode version.
Import¶
Import the framework in the classes that are going to use it. Import as import PolyNetSDK
in Swift and as #import <PolyNetSDK/PolyNetSDK.h>
in Objective C.
Connecting¶
The following parameters are needed for a successful integration with Our SDK:
- manifestUrl: The URL of the manifest video playlist.
- channelId: Optional identifier for the channel.
- apiKey: Api Key provided by System73. Contact us in order to obtain it.
- regex: Optional regex expression to mask user tokens in the media URLs.
Initialise an instance of the Edge Intelligence SDK object and uses its property localManifestUrl
to initialise the player.
// Strong reference to the SDK object.
var polyNet: PolyNet?
...
// Initialise
do {
let polyNet = try PolyNet(manifestUrl: manifestUrl,
channelId: channelId, apiKey: apiKey)
polyNet.delegate = self // Optional
polyNet.dataSource = self
self.polyNet = polyNet
polyNet.setPlayerInfo(name: "<PLAYER_NAME>", version: "<PLAYER_VERSION>")
// For example:
// polyNet.setPlayerInfo(name: "avplayer", version: "1.1.0")
// Init the player with the localManifestUrl property of the SDK instance
//
// For example:
// var player = AVPlayer(url: URL(string: polyNet.localManifestUrl)!)
} catch {
// The SDK CANNOT be used as there was an initialisation issue.
// Init the player with the original manifest URL.
//
// For example:
// var player = AVPlayer(url: URL(string: manifestUrl))
// Where manifestUrl is the original URL of the manifest.
}
Important
Initialise the player instance with the localManifestUrl
property of the SDK instance. Do not start the player with the original manifest URL, unless the SDK object fails to init.
List of initialisation errors¶
This is the list of the possible initialisation 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 SDK has failed to build. Detail: (...). If problem persists, contact support at support@system73.com. |
Providing metrics (PolyNetDataSource)¶
You MUST provide the Edge Intelligence SDK instance with some of the video player's metrics. To provide the metrics you need to conform and implement the PolyNetDataSource
protocol.
You will need to provide regular buffer health metrics, whenever requested, to make sure our service works properly. If you cannot obtain a metric from the player at the moment of the call, return nil
for that metric.
Each video player provides access to the metrics in different ways. The following code uses the AVFoundation player AVPlayer as an implementation example. Consider the player object being a AVPlayer instance.
// The Edge Intelligence SDK requests the buffer health of the video player.
// This is the current buffered time ready to be played.
func playerBufferHealth(in: PolyNet) -> NSNumber? {
// Get player time ranges. If not, return nil
guard let timeRanges: [NSValue] = player?.currentItem?.loadedTimeRanges,
timeRanges.count > 0,
let currentTime = player?.currentItem?.currentTime()
else {
return nil
}
// Get the valid time range from time ranges, return nil if not valid one.
guard let timeRange = getTimeRange(timeRanges: timeRanges, forCurrentTime: currentTime) else {
return nil
}
let end = timeRange.end.seconds
return max(end - currentTime.seconds, 0) as NSNumber
}
func getTimeRange(timeRanges: [NSValue], forCurrentTime time: CMTime) -> CMTimeRange? {
let timeRange = timeRanges.first(where: { (value) -> Bool in
CMTimeRangeContainsTime(value.timeRangeValue, time)
})
// Workaround: When pause the player, the item loaded ranges moves whereas the current time
// remains equal. In time, the current time is out of the range, so the buffer health cannot
// be calculated. For this reason, when there is not range for current item, the first range
// is returned to calculate the buffer with it.
if timeRange == nil && timeRanges.count > 0 {
return timeRanges.first!.timeRangeValue
}
return timeRange?.timeRangeValue
}
// The SDK requests the dropped video frames.
// This is the accumulated number of dropped video frames for the player.
func playerAccumulatedDroppedFrames(in: PolyNet) -> NSNumber? {
// If no events, return nil
guard let event = player?.currentItem?.accessLog()?.events.last else {
return nil
}
// Get the last event and return the dropped frames.
// If the value is negative, the value is unknown according to the API. In such cases return nil.
let numberOfDroppedVideoFrames = event.numberOfDroppedVideoFrames
if (numberOfDroppedVideoFrames < 0) {
return nil
} else {
return numberOfDroppedVideoFrames as NSNumber
}
}
// The SDK requests the started date of the playback.
// This is the date when the player started to play the video
func playerPlaybackStartDate(in: PolyNet) -> Date? {
// If no events, return nil
guard let event = player?.currentItem?.accessLog()?.events.last else {
return nil
}
return event.playbackStartDate
}
// The SDK requests the viewport size of the playback.
func playerViewportSize(in polyNet: PolyNet) -> CGSize? {
return playerLayer?.videoRect.size
}
// The SDK requests the video resolution of the playback.
func playerVideoResolution(in polyNet: PolyNet) -> CGSize? {
guard let track = player?.currentItem?.tracks.first else { return nil }
return track.assetTrack?.naturalSize
}
// The SDK requests the playback states(unknown, starting, playing, paused and buffering) of player.
func playerState(in polyNet: PolyNet) -> PolyNet.PolynetPlayerState {
return PolyNet.PolynetPlayerState.playing
}
Handling events (PolyNetDelegate) [Optional]¶
In order to receive errors or metrics from the SDK you shall conform to the PolyNetDelegate
protocol:
// Errors
func polyNet(_ polyNet: PolyNet, didFailWithError error: PolyNetError) {
// TODO: You may access the PolyNet Error object now.
}
// Metrics (This method is optional)
func polyNet(_ polyNet: PolyNet, didUpdateMetrics: PolyNetMetrics) {
// TODO: You may access the PolyNet Metrics object now.
}
The error method will be called when there is an error raised by our service. Nevertheless, the service will keep working as reliably as possible. This method is useful in the debugging of the integration process.
Content Steering¶
To access the optional content steering feature, you'll need to set a valid content steering resource in your SDK. You can obtain this resource URI from the ESP (Edge Service Platform) portal. To accomplish this, follow these steps:
- Create an instance of the Edge Intelligence SDK.
- Call the
init
method declared in the class. - Pass the parameter
contentSteeringEndpoint
into the init method obtained from the ESP portal. - By default content steering feature is enabled. By setting the content steering resource, you can enable or disable the content steering feature in your application.
// Pass your content steering resource to the init method declared in the class
do {
polyNet = try PolyNet(manifestUrl: manifestUrl, channelId: channelId == "" ? nil : channelId, apiKey: apiKey, contentSteeringEndpoint: contentSteeringEndpoint, managesEncryptionKeys: true)
} catch {
showAlertView(message: error.localizedDescription)
return
}
Remember to pass "contentSteeringEndpoint"
with the actual valid resource URI you obtained from the ESP portal.
Multi-Features¶
Content Steering¶
To control content steering in your application, you can utilize the SDK object. To enable or disable content steering, follow these steps:
- Create an instance of the Edge Intelligence SDK.
- Call the function named
enableContentSteering()
declared in the class. - Pass the value
true
toenableContentSteering()
method to enable content steering orfalse
to disable it. By default, if you provide a content steering resource, content steering will be enabled. Therefore, if you don't explicitly set the property, content steering will be enabled.
polyNet.enableContentSteering(true)
Peer to Peer¶
To control the availability of peer-to-peer in your application, follow these steps:
- Create an instance of the Edge Intelligence SDK.
- Call the
enableP2P()
method declared in the class. - Pass the value
true
toenableP2P()
method to enable peer-to-peer orfalse
to disable it. - By default, peer-to-peer is enabled, so if you don't explicitly modify the method, peer-to-peer functionality will remain enabled.
polyNet.enableP2P(true)
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 by calling PolyNetError
enum and then pass the enum case.
- For example
let error: PolyNetError = PolyNetError.internalError
. - When we print this
error
variable it will return error code-700
.
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 tracker provided. Tracker code: (...). This may happen in transitions to newer versions. If problem persists, contact support at support@system73.com. |
-702 | Error communicating with tracker. Detail: (...). If problem persists, contact support at support@system73.com. |
-703 | Error communicating with tracker metrics endpoint. Detail: (...). If problem persists, contact support at support@system73.com. |
-704 | The Api Key is revoked from PolyNet server. Please, contact support at support@system73.com. |
-705 | PolyNet connection rejected. Detail: (...). If problem persists, contact support at support@system73.com. |
-706 | Invalid or revoked content steering endpoint. Detail: (...). If problem persists, contact support at support@system73.com. |
The metrics method will be called periodically to deliver metrics.
The reported PolyNetMetrics
contain the following properties:
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 client. |
date | Date | The timestamp on which the metrics object was created. |
deviceId | String | Unique identifier for the device running the Edge Intelligence SDK. |
downSpeed | String | The last computed download speed. (Kilobits). |
inboundNodeId | String | Unique identifier for the inbound connection if connected to other peer or the value “POI” if downloading from CDN. |
isConnected | Boolean | A Boolean that identifies if the client is connected to Edge Intelligence. |
natType | String | The type of NAT. This depends on the device connection to Internet. |
nodeId | String | Unique identifier for the node when connected to the Edge Intelligence service. |
outboundMetrics | [PolynetOutboundMetrics] | Metrics for outbound peers. See PolynetOutboundMetrics below. |
playerBufferHealth | String | The amount of time (playback time) that are left for playing in the player's video read-ahead buffer. (milliseconds). |
playerTimeToFirstFrame | String | The amount of time from the start of the SDK until the player starts playback. (milliseconds). |
p2pDownThroughput | String | The amount of data as payload received from P2P during the last reporting period. (Kilobits). |
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. |
sessionId | String | Unique identifier for the device session running the SDK. |
source | String | The source specifies where the content is downloaded from. |
streamId | String | Unique identifier for the current stream being displayed. |
upSpeed | String | The last computed upload speed. (Kilobits). |
The PolynetOutboundMetrics
contain the following properties:
Name | Type | Description |
---|---|---|
bufferFillingRate | Number | The rate at which the content is received in the Edge Intelligence outbound peer versus playing time. |
nodeId | String | Unique identifier for the Edge Intelligence outbound peer. |
status | String | The status of the connection for the Edge Intelligence outbound peer. |
Extra custom dimensions [Optional]¶
Using custom dimensions, the System73 Edge Intelligence SDK allows you to report extra data that is not defined in the existing set of metrics.
At the moment, the SDK supports 3 extra custom dimensions. Each custom dimension is a String value, which you can populate with any custom data or metadata suited to your needs. Note this String value is limited to max. 256 characters, and will be trimmed down to this length.
// Set value of custom dimension string #1
polynet.customDimension1(customDimension1: "custom dimension string 1")
// Set value of custom dimension string #2
polynet.customDimension2(customDimension2: "custom dimension string 2")
// Set value of custom dimension string #3
polynet.customDimension3(customDimension3: "custom dimension string 3")
Disconnecting¶
To disconnect from our service, first invoke the method close
and then set to nil
.
polyNet?.close()
polyNet = nil
Warning
Once an Edge Intelligence SDK instance is closed, you CANNOT use it again.
If you want to connect to a new channel or the same channel, just go back to the initialisation steps and create a new instance.
Other considerations [Optional]¶
Manage encryption keys¶
You can use an advanced init method:
init(manifestUrl: String, channelId: String, apiKey: String, manageEncryptionKeys: Bool)
The property manageEncryptionKeys
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 Our 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
, Our SDK delegates to the player all Key files requests. This is useful when authentication is managed with cookies that need to be handled externally or prior the player is initialised. This property is set to true
by default on the basic init method
.
Sharing content restriction¶
Using the sharingContent
property you can control how your application will participate in our service's overlay. Its possible values are:
- never: The video content will never be shared with other peers.
- onlyOnLAN: The video content will be shared only if connected via WIFI or ETHERNET. (Default)
- always: The video content will be shared with other peers.
Use case
If you want to allow your users to opt in/out of P2P networking, you can set this property based on a control in your application.
Using cookies containing authentication tokens¶
The Edge Intelligence SDK uses the shared instance [NSHTTPCookieStorage sharedHTTPCookieStorage]
to store cookies. Those cookies could be used by the player to request additional resources, such as decryption keys. Modifying or removing those cookies may cause the stream not to be properly retrieved.
This section was last updated 2024-11-18