Skip to main content

API & Config

P2P Configuration

Create P2pConfig instance.

let config = P2pConfig()

The default fields (shown below) can be overridden.

FieldTypeDefaultDescription
trackerZoneTrackerZone.EuropeThe country enum for the tracker server address(Europe, HongKong, USA)
debugBoolfalseEnable or disable log
logLevelLogLevel.WARNPrint log level(VERBOSE, DEBUG, INFO, WARN, ERROR)
iceServers[IceServer][IceServer(url: "stun:stun.l.google.com:19302"), IceServer(url: "stun:global.stun.twilio.com:3478?transport=udp")]For WebRTC Stun Configuration
announceString?nilThe address of tracker server
diskCacheLimitUInt2000 1024 1024The max size of binary data that can be stored in the cache for VOD(Set to 0 will disable disk cache)
memoryCacheCountLimitUInt20The max count of ts files that can be stored in the memory cache
p2pEnabledBooltrueEnable or disable p2p engine
localPortHlsUInt0The port for local http server of HLS(Use random port by default)
customLabelString?${platform}-${system_version}Add a custom label to every different user session, which in turn will provide you the ability to have more meaningful analysis of the data gathered
maxPeerConnectionsInt25Max peer connections at the same time
useHttpRangeBooltrueUse HTTP ranges requests where it is possible. Allows to continue (and not start over) aborted P2P downloads over HTTP
useStrictHlsSegmentIdBoolfalseUse segment url based segment id instead of sequence number based one
httpHeadersHls[String : String]?nilSet HTTP Headers while requesting ts and m3u8
sharePlaylistBoolfalseAllow the P2P transmission of m3u8 file
prefetchOnlyBoolfalseOnly use prefetch strategy in p2p downloading
logPersistentBoolfalseSave logs to the file, default path is Library/Caches/p2pengine.log
geoIpPreflightBooltrueMake a preflight request to online Geo IP database provider to get ASN

P2pEngine

Initialize P2pEngine in AppDelegate.m:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
P2pEngine.setup(token: YOUR_TOKEN)
return true
}

Where token is your Customer ID, please replace it by your own token obtained from console.

let parsedUrl = P2pEngine.shared.parseStreamUrl(ORIGINAL_URL)

Switch Stream URL

When Switching to a new stream URL, before passing new stream url(m3u8) to the player, pass that URL through P2pEngine instance:

let newParsedURL = P2pEngine.shared.parseStreamUrl(NEW_ORIGINAL_URL)

Stop P2P

Stop p2p streaming of current source, but keep local proxy working:

override func viewDidDisappear(_ animated: Bool) {
P2pEngine.shared.stopP2p()
}

Disable P2P at runtime

it will not take effect until the next media file is played.

P2pEngine.shared.disableP2p()

Enable P2P at runtime

it will not take effect until the next media file is played.

P2pEngine.shared.enableP2p()

Stop P2P and Local Proxy

Stop p2p streaming of current source and local proxy:

P2pEngine.shared.shutdown()

Restart Local Proxy

P2pEngine.shared.startLocalServer()

P2P Statistics

Use P2pStatisticsMonitor to observe downloading statistics:

let monitor = P2pStatisticsMonitor(queue: .main)
P2pEngine.shared.p2pStatisticsMonitor = monitor

Then get the downloading statistics, including p2pDownloadedp2pUploadedhttpDownloadedpeersserverConnected

monitor.onPeers = { peers in
}
monitor.onP2pUploaded = { value in
}
monitor.onP2pDownloaded = { value, speed in
}
monitor.onHttpDownloaded = { value in
}
monitor.onServerConnected = { connected in
}
note

The unit of download and upload is KB.

Advanced Usage

Callback Player Stats

On Live streaming, to improve performance, we recommend to tell p2p engine the duration from the playback time to the end of the buffered interval. In order to do so, you need to implement PlayerInteractor .

class ViewController: UIViewController {
...
P2pEngine.shared.playerInteractor = self
...
}
extension ViewController : PlayerInteractor {
func onBufferedDuration() -> TimeInterval {
let currentTime = CMTimeGetSeconds(self.avplayer.currentTime())
var bufferedDuration: Double = 0.0
let timeRanges = self.avplayer.currentItem!.loadedTimeRanges
for value in timeRanges {
let timeRange = value.timeRangeValue
let start = CMTimeGetSeconds(timeRange.start)
let end = start + CMTimeGetSeconds(timeRange.duration);
if (currentTime >= start && currentTime <= end) {
bufferedDuration = end - currentTime;
break;
}
}
return bufferedDuration;
}
}

On the VOD mode, the duration of a video may be large. If we can match peers with similar playback time, it will help to improve the P2P performance, so we recommend to tell p2p engine the current playback time of player:

class ViewController: UIViewController {
...
P2pEngine.shared.playerInteractor = self
...
}
extension ViewController : PlayerInteractor {
func onCurrentPosition() -> TimeInterval {
return CMTimeGetSeconds(self.avplayer.currentTime())
}
}

Dynamic M3u8 Path Support

The channelId is an identifier used by our backend to match peers that are watching the same content. It is an optional parameter, and by default, we generate channelId from the content URL by removing any query parameters and protocol from it. Some m3u8 urls play the same live/vod but have different paths on them. For example, example.com/clientId1/streamId.m3u8 and example.com/clientId2/streamId.m3u8. In this case, you can format a common channelId for them.

let videoId = extractVideoIdFromUrl(url: orginalUrl)                      // extractVideoIdFromUrl 需要自己定义,可以抽取url中的视频ID作为结果返回
let parsedUrl = P2pEngine.shared.parseStreamUrl(orginalUrl, videoId: videoId)

Setup HTTP headers

Some HTTP requests need to add header information such as User-Agent for Anti-Leech or statistical requirements. It can be set via httpHeaders :

p2pConfig.httpHeadersHls = ["User-Agent": "XXX"]

Or set HTTP headers dynamically:

P2pEngine.shared.setHttpHeadersForHls(headers: ["User-Agent": "XXX"])

Work in AirPlay mode

SwarmCloud does not directly support AirPlay mode at the moment but it is easy to make it work in an app. The way to do this is to only use the Proxy URL when the app is not airplaying:

if (/* player is in AirPlay mode */) {
// set URL to original version
[player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:original]];
} else {
// airplay stopped - set URL to result of parseStreamURL
[player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:rewritten]];
}

Support additional media file type of HLS

By default, only common file types with suffix such as ".ts" are supported. If you need to support file types similar to ".image", you need to make the following configuration:

let config = P2pConfig()
config.hlsMediaFiles = ["ts", "image"]
P2pEngine.shared.setup(token: YOUR_TOKEN, config: config)

Generally, HLS media files end with ".xx", but there are exceptions. In order for the local proxy to recognize these extensions, the following configuration is required:

class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
func isMediaSegment(url: String) -> Bool {
return mediaFileRegex.match(url)
}
}

Bypass User-specific Segments

Sometimes we don't want some ts files to be shared, such as user-specific ts generated by SSAI (Server Side Ad Insertion). At this time, we can use the segmentBypass function to bypass it:

class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
func shouldBypassSegment(url: String) -> Bool {
return isSSAISegment(url)
}
}

Intercept playlist

The SDK will parse the contents of m3u8 when downloaded, if you use encrypted m3u8, you need to use the interceptor to intercept and return the standard m3u8 file:

class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
func interceptPlaylist(data: Data, url: String) -> Data {
return handlePlaylist(data, url)
}
}

Report Player Rebuffering

You may want to report the player rebuffering event to the sdk, then get average rebuffer ratio from SwarmCloud dashboard:

NotificationCenter.default.addObserver(self, selector: #selector(handleItemPlayBackStall), name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: player.currentItem)

@objc func handleItemPlayBackStall() {
P2pEngine.shared.notifyPlaybackStalled()
}