Skip to content

iOS SDK

This document applies to our SDK version 5 for iOS and tvOS. Its sample code is written in Swift 5.

Requirements

iOS 9.0 or later, tvOS 9.0 or later, and the Latest Xcode version.

Important

If the application has a Deployment Target for iOS 8 (or lower), or tvOS 8 (or lower), you will need to provide an optional integration, where our SDK is not used in those versions.

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.

Initialise an instance of PolyNet object and uses its property localManifestUrl to initialise the player.

// Strong reference to the PolyNet 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
    // Init the player with the localManifestUrl property of the PolyNet
    //
    // For example:
    // var player = AVPlayer(url: URL(string: polyNet.localManifestUrl)!)
} catch {
    // The PolyNet 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 PolyNet instance. Do not start the player with the original manifest URL, unless the PolyNet object fails to init.

Providing metrics (PolyNetDataSource)

You MUST provide the PolyNet 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.

// PolyNet 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
}

// PolyNet 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
   }
}

// PolyNet request 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
}

Handling events (PolyNetDelegate) [Optional]

In order to receive errors or metrics from the PolyNet 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.

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 PolyNet 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 Bool A boolean that identifies if the PolyNet client is connected to Tracker.
natType String The type of NAT. This depends on the device connection to Internet.
nodeId String Unique identifier for the PolyNet client when connected to Tracker.
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 PolyNet 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 PolyNet 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 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

To disconnect from our service, first invoke the method close and then set to nil.

polyNet?.close()
polyNet = nil

Warning

Once a PolyNet 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 PolyNetSDK 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.