API & Config
# Introduction
CDNBye implements WebRTC (opens new window) datachannel to scale live/vod video streaming by peer-to-peer network using bittorrent-like protocol.
To use CDNBye hlsjs-p2p-engine, WebRTC support is required (Chrome, Firefox, Opera, Safari).
# Use Hls.js wrapped with P2PEngine
# Hls.engineVersion (static method)
Show the current version of CDNBye plugin.
# Hls.WEBRTC_SUPPORT (static method)
Is WebRTC natively supported in the environment?
if (Hls.WEBRTC_SUPPORT) {
// WebRTC is supported
} else {
// Use a fallback
}
# Create Hls instance
# var hls = new Hls({p2pConfig: [opts]});
Create a new Hls instance.
# var engine = hls.p2pEngine;
Get the P2PEngine instance from Hls instance.
If opts is specified, then the default options (shown below) will be overridden.
Field | Type | Default | Description |
---|---|---|---|
logLevel | string|boolean | 'error' | Print log level(warn, error, none,false=none, true=warn). |
token | string | undefined | tokenis used to summarize and display multi domain name data on the console. In addition, token is required while customizing channelId. |
live | boolean | true | tell engine whether in live or VOD mode. |
trackerZone | string | 'eu' | The country code name of the tracker server address('eu', 'hk', 'us'). |
memoryCacheLimit | Object | {"pc": 400 * 1024 * 1024, "mobile": 100 * 1024 * 1024} | The max size of binary data that can be stored in the cache. |
p2pEnabled | boolean | true | Enable or disable p2p engine. |
webRTCConfig | Object | {} | A Configuration dictionary (opens new window) providing options to configure WebRTC connections. |
useHttpRange | boolean | true | Use HTTP ranges requests where it is possible. Allows to continue (and not start over) aborted P2P downloads over HTTP. |
waitForPeer | boolean | false | Try downloading initial segments over P2P, giving the peers extra time to download initial segments will increase the p2p Ratio. |
waitForPeerTimeout | number | 4.5 | HTTP will be forcibly enabled if there is no peers on tracker or waitForPeerTimeout is timed out. |
httpLoadTime | number | 2.0 | Time for HTTP download if p2p download timeout. |
sharePlaylist | boolean | false | Allow the P2P transmission of m3u8 file. |
showSlogan | boolean | false | Display slogan of cdnbye on console. |
geoIpPreflight | boolean | true | Make a preflight request to online Geo IP database provider to get ASN and geo-related information. |
# P2PEngine API
# P2PEngine.version (static)
Get the version of P2PEngine.
# P2PEngine.protocolVersion (static)
Get the version of P2P protocol,only have the same protocol version as another platform can both interconnect with each other.
# P2PEngine.isSupported() (static method)
Returns true if WebRTC data channel is supported by the browser.
# var engine = new P2PEngine(hlsjs, p2pConfig);
Create a new P2PEngine instance. Or you can get P2PEngine instance from hlsjs:
var hls = new Hls();
var engine = hls.p2pEngine;
# engine.enableP2P()
Resume P2P if it has been stopped.
# engine.disableP2P()
Disable engine to stop p2p and free used resources.
# engine.destroy()
Stop p2p and free used resources, it will be called automatically before hls.js is destroyed.
# P2PEngine Events
# engine.on('peerId', function (peerId) {})
Emitted when the peer Id of this client is obtained from server.
# engine.on('peers', function (peers) {})
Emitted when successfully connected with new peer.
# engine.on('stats', function (stats) {})
Emitted when data is downloaded/uploaded.
stats.totalHTTPDownloaded: total data downloaded by HTTP(KB).
stats.totalP2PDownloaded: total data downloaded by P2P(KB).
stats.totalP2PUploaded: total data uploaded by P2P(KB).
stats.p2pDownloadSpeed: p2p download speed(KB/s).
# engine.on('serverConnected', function (connected) {})
Emitted when websocket is opened/closed.
# engine.on('exception', function (e) {})
Emitted when exception occured.
e.code: Exception identifier(TRACKER_EXPT SIGNAL_EXPT HLSJS_EXPT)
e.message: Exception message
e.stack: Exception stack
# Get p2p information from p2pConfig
p2pConfig: {
getStats: function (totalP2PDownloaded, totalP2PUploaded, totalHTTPDownloaded, p2pDownloadSpeed) {
// get the downloading statistics
},
getPeerId: function (peerId) {
// get peer Id
},
getPeersInfo: function (peers) {
// get peers information
}
}
# Advanced Usage
# 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.
// Set token in p2pConfig before setting channelId! Connectivity with other platform should have the same token and channelId.
p2pConfig: {
token: YOUR_TOKEN,
channelId: function (m3u8Url) {
const videoId = extractVideoIdFromUrl(m3u8Url); // make a channelId by removing the different part which is defined by yourself
return videoId;
}
// channelId: VIDEO_ID // for fixed channel id
}
Let's say your m3u8 is http://example.com/token123456/video1/playlist.m3u8, in which token123456 is the token varied by users, video1 is the ID of the video.
p2pConfig: {
token: YOUR_TOKEN,
channelId: function (m3u8Url) {
var parts = m3u8Url.split('/');
var videoId = parts[parts.length-2]+'/'+parts[parts.length-1];
return videoId;
}
}
The following is an example of the client behaviour with this channelId configured:
<!-- URL to be replaced -->
http://example.com/token123456/video1/playlist.m3u8
<!-- Resulting channelId -->
video1/playlist.m3u8
Interconnect with other platform should ensure that both have the same token and channelId.
# Dynamic Ts Path Support
Like dynamic m3u8 path, you should format a common segmentId for the same ts file. You can override the segment ID like this:
p2pConfig: {
/*
streamId: The id of stream
sn: The serial number of segment
segmentUrl: The url of segment
*/
segmentId: function (streamId, sn, segmentUrl, range) {
const tsId = extractSegmentIdFromUrl(segmentUrl);
return tsId;
}
}
# P2P First Strategy
Since it takes time to establish a P2P connection, the first few pieces are downloaded using HTTP by default. Giving the peers extra time to download initial segments will increase the p2p ratio. However, it may cause delay. It is recommended to turn on the hot channel.
p2pConfig: {
waitForPeer: true,
waitForPeerTimeout: 4.5, // Http will be forcibly enabled if there is no peers on tracker or waitForPeerTimeout is timed out
}
Multi-Bitrate HLS is not supported.
# Allow Http Range Request
If http range request is activated, we are able to get chunks of data from peer and then complete the segments by getting other chunks from the CDN, thus, reducing your CDN bandwidth. To activate range requests, See Allow Http Range Request. Besides, the code below is needed:
p2pConfig: {
useHttpRange: true,
}
# Use Your Own STUN or TURN Server
STUN (Session Traversal Utilities for NAT) allows clients to discover their public IP address and the type of NAT they are behind. This information is used to establish the media connection. Although there are default STUN servers in this SDK, you can replace them with your own via P2PConfig. TURN (Traversal Using Relays around NAT) server is used to relay traffic if direct connection fails. You can config your TURN (opens new window) server in the same way as STUN.
p2pConfig: {
webRTCConfig: {
iceServers: [
{ urls: YOUR_STUN_OR_TURN_SERVER }
]
}
}
# How to Check Segment Validity
Sometimes we need to prevent a peer from sending a fake segment (such as the bittorrent with a hash function). CDNBye provides a validation callback with buffer of the downloaded segment, developer should implement the actual validator. For example, you can create a program that generates hashes for the segments and stores them in a specific file or injects into m3u8 playlist files the hashes information. If the callback returns false, then the segment is not valid.
p2pConfig: {
validateSegment: function (segId, buffer) {
var hash = hashFile.getHash(segId);
return hash === md5(buffer);
}
}