API & Config
# P2P Configuration
A P2pConfig can be obtained via its builder, the parameters below is the default values:
P2pConfig config = new P2pConfig.Builder()
.logEnabled(false) // Enable or disable log
.logLevel(LogLevel.WARN) // Print log level
.announce("https://tracker.cdnbye.com/v1") // The address of tracker server
.AnnounceLocation(AnnounceLocation.Europe) // The country enum for the tracker server address(Europe, HongKong, USA).
.downloadTimeout(30_000, TimeUnit.MILLISECONDS) // TS file download timeout by HTTP
.localPortHls(0) // The port for local http server of HLS(Use random port by default, set -1 to disable Hls local proxy service)
.localPortMp4(0) // The port for local http server of MP4(Use random port by default, set -1 to disable Mp4 local proxy service)
.localPortDash(0) // The port for local http server of DASH(Use random port by default, set -1 to disable Dash local proxy service)
.diskCacheLimit(1500*1024*1024) // The max size of binary data that can be stored in the disk cache for VOD(Set to 0 will disable disk cache)
.memoryCacheCountLimit(30) // The max count of ts files that can be stored in the memory cache
.p2pEnabled(true) // Enable or disable p2p engine
.withTag(null) // 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
.webRTCConfig(null) // Providing options to configure WebRTC connections
.maxPeerConnections(20) // Max peer connections at the same time
.useHttpRange(true) // Use HTTP ranges requests where it is possible. Allows to continue (and not start over) aborted P2P downloads over HTTP
.httpHeadersForHls(null) // Set HTTP Headers while requesting ts and m3u8.
.httpHeadersForMp4(null) // Set HTTP Headers while requesting MP4.
.httpHeadersForDash(null) // Set HTTP Headers while requesting DASH manifest and media file.
.httpHeadersForFile(null) // Set HTTP Headers for file downloading.
.isSetTopBox(false) // Set it as true if SDK is running on set-top box
.fileCacheDirectory(null) // File download cache directory. Cache directory will be created on SD card("/Android/data/[app_package_name]/cache") if card is mounted and app has appropriate permission or on device's file system depending incoming parameters
.pieceLengthForMp4(1024*1024) // The piece legth for mp4 transporting
.pieceLengthForFile(1024*1024) // The piece legth for file transporting
.waitForPeer(false) // Try downloading initial segments over P2P, giving the peers extra time to download initial segments will increase the p2p Ratio.
.waitForPeerTimeout(4500) // HTTP will be forcibly enabled if there is no peers on tracker or waitForPeerTimeout is timed out.
.httpLoadTime(2_000) // Time for HTTP download if p2p download timeout.
.sharePlaylist(false) // Allow the P2P transmission of m3u8 file.
.logPersistent(false) // Save logs to the file({Environment.getExternalStorageDirectory()}/logger/).
.geoIpPreflight(true) // Make a preflight request to online Geo IP database provider to get ASN, only work for live mode.
.build();
P2pEngine.init(getApplicationContext(), token, config);
# P2pEngine
Instantiate P2pEngine,which is a singleton:
P2pEngine engine = P2pEngine.init(Context context, String token, P2pConfig config);
Explanation:
param | type | required | description |
---|---|---|---|
context | Context | Yes | The instance of Application Context is recommended. |
token | String | Yes | Token assigned by CDNBye. |
config | P2pConfig | No | Custom configuration. |
# Switch Stream URL
When Switching to a new stream URL, before passing new stream url to the player, pass that URL through P2pEngine instance:
String newParsedURL = P2pEngine.getInstance().parseStreamUrl(url);
# P2pEngine API
# P2pEngine.Version
Current SDK version.
# P2pEngine.protocolVersion
Get the version of P2P protocol,only have the same protocol version as another platform can both interconnect with each other.
# P2pEngine.getInstance()
Get the singleton of P2pEngine.
# engine.parseStreamUrl(String url)
Convert original playback address (m3u8, mp4) to the address of the local proxy server.
# engine.parseStreamUrl(String url, String videoId)
Convert original playback address (m3u8, mp4) to the address of the local proxy server, and pass video ID for making channel ID.
# engine.parseStreamUrl(String url, String videoId, MimeType mimeType)
If your URI doesn’t end with .m3u8/.mpd, you can pass MimeType.APPLICATION_M3U8 or MimeType.APPLICATION_MPD to the third parameter of parseStreamUrl to explicitly indicate the type of the content.
# engine.isConnected()
Check if connected with CDNBye backend.
# engine.stopP2p()
Once the video is done playing, you have to stop the P2P streaming you created earlier. Calling this method will finish the ongoing tasks and release the resources.
# engine.restartP2p()
Resume P2P if it has been stopped.
# engine.getPeerId()
Get the peer ID of this engine.
# engine.setHttpHeadersForHls(Map<String, String> headers)
Set HTTP Headers while requesting ts and m3u8 dynamically.
# engine.setHttpHeadersForMp4(Map<String, String> headers)
Set HTTP Headers while requesting mp4 dynamically.
# engine.setHttpHeadersForFile(Map<String, String> headers)
Set HTTP Headers for file download dynamically.
# engine.disableP2p()
P2P will be disabled dynamically at runtime, it will not take effect until the next media file is played.
# engine.enableP2p()
P2P will be enabled dynamically at runtime, it will not take effect until the next media file is played.
# engine.shutdown()
Stop P2P and shut down the proxy server.
# engine.downloadFile(String url)
Start file download.
Return instance of DownloadInfo ,including:
long getFileSize() : Get the total length of file
String getUrl() : Get the file url
String getFileName() : Get file name
String getMimeType() : Get MimeType from http response
File getCacheFile() : Get cache path of downloaded file
boolean isCached() : Is the file already cached
boolean isInProgress() : Is the file download in progress
# engine.downloadFile(String url, String fileName)
Start download file from url,specify a filename.
# engine.downloadFile(String url, String fileName, File cacheDir)
Start download file from url,specify a filename and the cache file directory.
# engine.downloadFile(String url, String fileName,String channelId)
Start download file from url,specify a filename and channelId for p2p.
# engine.downloadFileNormally(String url)
Download file normally without p2p.
# engine.stopFileDownload()
Stop file download, stop p2p and free used resources.
# engine.pauseFileDownload()
Pause file download.
# engine.deleteDownloadedFile(File file)
Delete files being downloaded or downloaded.
# P2P Statistics
Add a observer P2pStatisticsListener to observe downloading statistics:
engine.addP2pStatisticsListener(new P2pStatisticsListener() {
@Override
public void onHttpDownloaded(long value) {
}
@Override
public void onP2pDownloaded(long value, int speed) {
}
@Override
public void onP2pUploaded(long value, int speed) {
}
@Override
public void onPeers(List<String> peers) {
}
@Override
public void onServerConnected(boolean connected) {
}
});
The unit of download and upload is KB. The unit of download speed is KB/s.
# File Download Listener
engine.registerFileDownloadListener(new FileDownloadListener() {
@Override
public void onDownloadFailed(Throwable e) {
// fallback
}
@Override
public void onDownloadFinished(File cacheFile, String url) {
// get downloaded file here
}
@Override
public void onCacheAvailable(File cacheFile, String url, int percentsAvailable) {
// show progress to user
}
});
# Remove File Download Listener
engine.unregisterFileDownloadListener(FileDownloadListener listener)
# Advanced Usage
# Callback Player Stats
On HLS Live streaming or mp4 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 use callback setPlayerInteractor .
import com.cdnbye.core.p2p.PlayerInteractor;
P2pEngine.getInstance().setPlayerInteractor(new PlayerInteractor() {
public long onBufferedDuration() {
// Exoplayer in milliseconds
return player.getBufferedPosition() - player.getCurrentPosition();
}
});
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:
import com.cdnbye.core.p2p.PlayerInteractor;
P2pEngine.getInstance().setPlayerInteractor(new PlayerInteractor() {
public long onCurrentPosition() {
// Exoplayer in milliseconds
return player.getCurrentPosition();
}
});
# Dynamic Url 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 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.
- HLS & DASH & MP4
String videoId = extractVideoIdFromUrl(urlString); // extractVideoIdFromUrl is a function defined by yourself, you just need to extract video id from url
String parsedUrl = P2pEngine.getInstance().parseStreamUrl(urlString, videoId);
- File download
String fileId = extractFileIdFromUrl(urlString); // extractFileIdFromUrl is a function defined by yourself, you just need to extract file id from url
P2pEngine.getInstance().downloadFile(url, url, fileId);
Interconnect with other platform should ensure that both have the same token and channelId.
# Dynamic Media File Path Support
Like dynamic m3u8/mpd path, you should format a common segmentId for the same media file. You can override the segment ID like this:
/*
streamId: The id of stream
sn: The serial number of segment
segmentUrl: The url of segment
range: Byte range of segment
*/
// For HLS
P2pEngine.getInstance().setHlsSegmentIdGenerator(new HlsSegmentIdGenerator() {
@Override
public String onSegmentId(String streamId, long sn, String segmentUrl, String range) {
return extractIdFromSegment(segmentUrl, range);
}
});
// For DASH
P2pEngine.getInstance().setDashSegmentIdGenerator(new DashSegmentIdGenerator() {
@Override
public String onSegmentId(String streamId, String segmentUrl, String range) {
return extractIdFromSegment(segmentUrl, range);
}
});
# 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 setHttpHeaders :
Map headers = new HashMap();
headers.put("User-Agent", "XXX");
engine.setHttpHeadersForHls(headers); // For hls playback
// engine.setHttpHeadersForDash(headers); // For dash playback
// engine.setHttpHeadersForMp4(headers); // For mp4 playback
// engine.setHttpHeadersForFile(headers); // For file download
# Pass your Customized OkHttpClient
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new YourInterceptor())
.build();
P2pConfig config = new P2pConfig.Builder()
.okHttpClient(httpClient)
.build();
# 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:
P2pConfig config = new P2pConfig.Builder()
.hlsMediaFiles(new ArrayList<String>(){{
add("mp4");
add("ts");
add("m4s");
add("m4v");
add("image");
}})
.build();
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:
// let's say media file url is http://example.com/pathxxx
P2pConfig config = new P2pConfig.Builder()
.hlsMediaFileExtensions(new ArrayList<String>(){{
add("xxx");
}})
.build();
# 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 config = new P2pConfig.Builder()
.waitForPeer(true)
.waitForPeerTimeout(4500) // Http will be forcibly enabled if there is no peers on tracker or waitForPeerTimeout is timed out
.build();
MPEG-DASH and Multi-Bitrate HLS is not supported.
# Intercept m3u8
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:
P2pEngine.getInstance().setHlsInterceptor(new HlsInterceptor() {
@Override
public byte[] interceptPlaylist(byte[] text, String url) {
return handlePlaylist(text, url);
}
});
# 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.
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnection.RTCConfiguration;
List<PeerConnection.IceServer> iceServers = new ArrayList<>();
iceServers.add(PeerConnection.IceServer.builder(YOUR_STUN_OR_TURN_SERVER).createIceServer());
RTCConfiguration rtcConfig = new RTCConfiguration(iceServers);
P2pConfig config = new P2pConfig.Builder()
.webRTCConfig(rtcConfig)
.build();
# Listen to SDK Exception
Due to network, server, algorithm bugs and other reasons, the SDK may have exceptions. You can listen to the exceptions by using the registerExceptionListener :
P2pEngine.getInstance().registerExceptionListener(new EngineExceptionListener() {
@Override
public void onTrackerException(EngineException e) {
// Tracker Exception
}
@Override
public void onSignalException(EngineException e) {
// Signal Server Exception
}
@Override
public void onSchedulerException(EngineException e) {
// Scheduler Exception
}
@Override
public void onOtherException(EngineException e) {
// Other Exception
}
});