P2pEngineHls API
var engine = new P2pEngineHls(p2pConfig);
实例化 P2pEngineHls。
如果指定了 p2pConfig ,那么对应的默认值将会被覆盖。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
hlsjsInstance | Hlsjs | null | Hlsjs的实例化对象,如果没有传入则不会启用基于 Hlsjs 的引擎。 |
proxyOnly | boolean | false | 是否强制启用基于 ServiceWorker 的引擎。 |
logLevel | string|boolean | 'error' | log的等级,分为'warn'、'error'、'none',设为true等于'warn',设为false等于'none'。 |
token | string | undefined | token用于控制台多域名数据汇总展示,另外如果自定义channelId也需要设置token。 |
live | boolean | true | 设置直播或者点播模式,不同模式会自动设置不同的hls.js参数。 |
announce | string | 'https://cn.cdnbye.com/v1' | tracker服务器地址。 |
trackerZone | string | 'eu' | tracker服务器地址的国家代号,分为'cn'、'eu'、'hk'、'us'。 |
memoryCacheLimit | Object | {"pc": 400 * 1024 * 1024, "mobile": 100 * 1024 * 1024} | 内存缓存的最大数据量,分为PC和mobile。 |
p2pEnabled | boolean | true | 是否开启P2P。 |
webRTCConfig | Object | {} | 用于配置stun和datachannel的字典。 |
useHttpRange | boolean | true | 在可能的情况下使用Http Range请求来补足p2p下载超时的剩余部分数据。 |
sharePlaylist | boolean | false | 是否允许m3u8文件的P2P传输。 |
strictSegmentId | boolean | false | 使用基于url的SegmentId,替代默认基于序列号的。 |
geoIpPreflight | boolean | true | 向在线IP数据库请求ASN等信息,从而获得更准确的调度,会延迟P2P启动时间。 |
swAutoRegister | boolean | true | 是否在初始化基于 ServiceWorker 的引擎后自动注册 ServiceWorker 。 |
swFile | string | './sw.js' | ServiceWorker文件名和路径。 |
swScope | string | './' | ServiceWorker默认作用域是当前目录以及所有子目录,因此如果将 sw.js 放在网站根目录,那么所有网站请求都在 ServiceWorker 控制范围内。 |
mediaElem | HTMLMediaElement|string | undefined | 指定media标签的id或者Element对象,默认是document中的第一个video或audio元素。 |
useDiskCache | boolean | true | 点播模式用 IndexedDB 存储数据。 |
diskCacheLimit | Object | {"pc": 1500 * 1024 * 1024, "mobile": 1000 * 1024 * 1024} | 磁盘缓存的最大数据量,分为PC和mobile。 |
prefetchOnly | boolean | false | 只采用预加载的方式进行P2P下载。 |
P2pEngineHls 属性和方法
P2pEngineHls.version (static)
获取 SDK 的版本号。
P2pEngineHls.protocolVersion (static)
获取 P2P 协议的版本号,与其他平台互通的前提是 P2P 协议版本号相同。
P2pEngineHls.HlsjsEngine (static)
获取基于 Hlsjs 的 P2pEngine 的构造函数。
P2pEngineHls.ServiceWorkerEngine (static)
获取基于 ServiceWorker 的 P2pEngine 的构造函数。
P2pEngineHls.tryRegisterServiceWorker(config) (static)
用于注册 ServiceWorker 的静态方法,如果指定了 config ,那么对应的默认值将会被覆盖。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
swFile | string | './sw.js' | ServiceWorker文件名和路径。 |
swScope | string | './' | ServiceWorker默认作用域是当前目录以及所有子目录。 |
P2pEngineHls.getBrowser() (static)
获取浏览器的名称,可能取值如下:
- Chrome
- Firefox
- Mac-Safari
- iOS-Safari
- X5
- Unknown
P2pEngineHls.isSupported() (static method)
判断当前浏览器是否支持WebRTC data channel ,以及 MSE 或者 SeviceWorker 其中之一。
P2pEngineHls.isMSESupported() (static)
判断当前浏览器是否支持 MEDIA SOURCE EXTENSIONS 。
P2pEngineHls.isServiceWorkerSupported() (static)
判断当前浏览器是否支持 ServiceWorker 。
engine.realEngine
获取目前启用的内部引擎实例。
engine.engineName
获取目前启用的内部引擎的名称,可能取值如下:
- HlsjsP2pEngine
- HlsSwP2pEngine
engine.enableP2P()
在p2p暂停或未启动情况下启动p2p。
engine.disableP2P()
停止p2p并释放内存。
engine.destroy()
停止p2p、销毁engine并释放内存。在Hls.js销毁时会自动调用。
engine.registerServiceWorker()
注册 ServiceWorker 并返回一个 promise 。
engine.unregisterServiceWorker()
销毁 ServiceWorker 并返回一个 promise 。
P2pEngineHls事件
engine.on('peerId', function (peerId) {})
当从服务端获取到peerId时回调该事件。
engine.on('peers', function (peers) {})
当与新的节点成功建立p2p连接时回调该事件。
engine.on('stats', function (stats) {})
该回调函数可以获取p2p信息,包括:
stats.totalHTTPDownloaded: 从HTTP(CDN)下载的数据量(单位KB)
stats.totalP2PDownloaded: 从P2P下载的数据量(单位KB)
stats.totalP2PUploaded: P2P上传的数据量(单位KB)
stats.p2pDownloadSpeed: P2P下载速度(单位KB/s)
engine.on('serverConnected', function (connected) {})
当连接/断开websocket时回调该事件。
engine.on('exception', function (e) {})
该回调函数可以获取SDK的异常信息,包括:
e.code: 异常标识(TRACKER_EXPT SIGNAL_EXPT HLSJS_EXPT)
e.message: 异常信息
e.stack: 异常堆栈信息
通过p2pConfig获取p2p信息
p2pConfig: {
getStats: function (totalP2PDownloaded, totalP2PUploaded, totalHTTPDownloaded, p2pDownloadSpeed) {
// 获取p2p下载信息
},
getPeerId: function (peerId) {
// 获取本节点的Id
},
getPeersInfo: function (peers) {
// 获取成功连接的节点的信息
},
onHttpDownloaded: function (traffic) {
// 监听http下载流量
},
onP2pDownloaded: function (traffic, speed) {
// 监听p2p下载流量和速度
},
onP2pUploaded: function (traffic) {
// 监听p2p上传流量
},
}
WARNING
下载和上传数据量的单位是KB,下载速度的单位是KB/s。
在Hls.js增加的新API
Hls.engineVersion (static method)
当前插件的版本号
Hls.WEBRTC_SUPPORT (static method)
判断当前浏览器是否支持WebRTC
if (Hls.WEBRTC_SUPPORT) {
// WebRTC is supported
} else {
// Use a fallback
}
Hls.P2pEngine (static method)
从Hls获取 P2pEngine ,等价于直接引入的 P2pEngineHls
实例化与参数配置
var hls = new Hls({p2pConfig: [opts]});
创建一个新的Hls
实例。其中 p2pConfig 等价于传入 P2pEngineHls 的 p2pConfig ,此时无需再指定 hlsjsInstance
hls.p2pEngine
从 Hls 实例中获取 P2pEngineHls 实例。
HlsProxy API
new HlsProxy(config);
创建一个 HlsProxy 实例。
如果指定了 config ,那么对应的默认值将会被覆盖。
字段 | 类型 | 默认值 | 描述 |
---|---|---|---|
httpHeadersForPlaylist | function(url, headers) | null | 设置m3u8请求的自定义http头,如:httpHeadersForPlaylist: (url, headers) => { headers.set('token', 'xxx') } |
httpHeadersForMediaFile | function(url, headers) | null | 设置ts请求的自定义http头,如:httpHeadersForMediaFile: (url, headers) => { headers.set('token', 'xxx') } |
insertTimeOffsetTag | boolean | false | 仅在直播模式生效,在m3u8文件中插入 "#EXT-X-START:TIME-OFFSET=[playlistTimeOffset]",强制播放器从某个位置开始加载 |
playlistTimeOffset | number | 0.01 | 仅在insertTimeOffsetTag=true时生效,如果为负则从播放列表结尾往前偏移(单位:秒) |
allowedMediaFiles | Array | ['ts', 'mp4', 'm4s', 'fmp4'] | 需要支持的媒体文件后缀,如 ['txt', 'png'],如果无后缀,可以设置 ['*'] |
mediaFileSeparator | String | '.' | 媒体文件后缀分隔符 |
allowedPlaylistSuffix | Array | ['m3u8'] | 需要支持的额外的播放列表文件后缀,如 ['txt'] |
HlsProxy.version (static)
获取 HlsProxy 的版本号。
高级用法
解决动态m3u8路径问题
某些流媒体提供商的m3u8是动态生成的,不同节点的m3u8地址不一样,例如example.com/clientId1/streamId.m3u8和example.com/clientId2/streamId.m3u8,而本插件默认使用m3u8地址(去掉查询参数)作为channelId。这时候就要构造一个共同的chanelId,使实际观看同一直播/视频的节点处在相同频道中。
// 必须先在 p2pConfig 设置 token ,才能自定义 channelId ! 与其他平台互通需要相同的 token 和 channelId 。
p2pConfig: {
token: YOUR_TOKEN,
channelId: function (m3u8Url) {
const videoId = extractVideoIdFromUrl(m3u8Url); // 忽略差异部分,构造一个一致的channelId,其中 extractVideoIdFromUrl 需要自己定义,可以抽取url中的视频ID作为结果返回
return videoId;
}
// channelId: VIDEO_ID // for fixed channel id
}
用 http://example.com/token123456/video1/playlist.m3u8 来举例, 其中 token123456 是根据不同用户产生的token,video1 是视频的唯一ID。
p2pConfig: {
token: YOUR_TOKEN,
channelId: function (m3u8Url) {
var parts = m3u8Url.split('/');
var videoId = parts[parts.length-2]+'/'+parts[parts.length-1];
return videoId;
}
}
按如上配置后,结果如下,token被去掉,只保留video ID:
<!-- URL to be replaced -->
http://example.com/token123456/video1/playlist.m3u8
<!-- Resulting channelId -->
video1/playlist.m3u8
WARNING
如果要与其他平台互通,则必须确保两者拥有相同的 token 和 channelId 。
P2P优先策略
由于建立P2P连接需要时间,默认情况下前几片用HTTP下载。可以通过配置参数,等待P2P建立连接后优先用P2P下载,从而提升P2P效果,但可能会带来延时,建议在热度比较大的频道开启。
p2pConfig: {
waitForPeer: true,
waitForPeerTimeout: 4.0, // 可以根据具体场景设置超时时间
sourceUrl: M3U8_URL, // m3u8地址, 如:'http://xxx.m3u8'
}
允许Http Range请求
当对等端上行带宽不够时,可能导致p2p传输超时而转向http下载,原本p2p下载的数据无法复用。Http Range请求用于补足p2p下载超时的剩余部分数据,要开启Http Range,首先需要源服务器支持,请参考允许Http Range请求,然后增加以下配置:
p2pConfig: {
useHttpRange: true,
}
屏蔽某些特殊的切片文件
某些情况下我们不想让某些切片文件参与P2P,比如SSAI(Server Side Ad Insertion)产生的特定于用户的切片,这个时候可以利用 segmentBypass 这个函数来进行过滤:
p2pConfig: {
segmentBypass: (url, tags) => {
return isSSAISegment(url)
},
}
在 sw.js 设置播放时间偏移量
通过在m3u8设置一个特殊的tag,可以强制播放器从列表开始位置加载,从而提升P2P效果,但同时会增加延迟,需要权衡考虑。
// sw.js
self.importScripts('https://cdn.jsdelivr.net/npm/@swarmcloud/hls/hls-proxy.js')
new HlsProxy({
insertTimeOffsetTag: true,
playlistTimeOffset: 0.01,
})
如何在 Service Worker 模式下支持更多文件后缀?
sw.js默认支持的 playlist 后缀是 m3u8 ,默认支持的媒体文件后缀是 'ts', 'mp4', 'm4s', 'fmp4' ,如果需要支持更多后缀,可以自定义配置:
self.importScripts('https://cdn.jsdelivr.net/npm/@swarmcloud/hls/hls-proxy.js')
new HlsProxy({
allowedPlaylistSuffix: ['m3u8', 'html'], // 如果需要支持的播放列表 url 是 xxx.html
allowedMediaFiles: ['ts', 'mp4', 'm4s', 'fmp4', 'jpg'], // 如果需要支持的媒体文件 url 是 xxx.jpg
// allowedMediaFiles: ['*'] // 如果没有后缀
})
自行配置 STUN 和 TURN 服务器地址
STUN用于p2p连接过程中获取公网IP地址,TURN则可以在p2p连接不通时用于中转数据。本SDK已内置公开的STUN服务,开发者可以通过P2pConfig来更换STUN地址。TURN服务器则需要开发者自行搭建,可以参考coturn。
p2pConfig: {
webRTCConfig: {
iceServers: [
{ urls: YOUR_STUN_OR_TURN_SERVER }
]
}
}
切片Hash校验
有时候我们需要校验从节点下载的切片的合法性(类似bittorrent的哈希校验)。 SDK提供了一个钩子函数,可以回调下载的切片供开发者进行校验。用于校验的 哈希表建议直接从服务器下载,开发者可以通过程序计算每个ts文件的哈希并存储于 特定的文件中或者直接嵌入到m3u8文件中。如果校验失败,直接在回调函数中 返回false即可。
p2pConfig: {
validateSegment: function (segId, buffer) {
var hash = hashFile.getHash(segId);
return hash === md5(buffer);
}
}