Skip to content

简介

CDNBye通过WebRTC datachannel技术和BT算法,在观看同一视频/直播的用户之间构建P2P网络,在节省带宽成本的同时,提升用户的播放体验。

采用本插件的前提是浏览器支持WebRTC (Chrome, Firefox, Opera, Safari)。

在Hls.js增加的新API

Hls.engineVersion (static method)

当前插件的版本号

Hls.WEBRTC_SUPPORT (static method)

判断当前浏览器是否支持WebRTC

javascript
if (Hls.WEBRTC_SUPPORT) {
  // WebRTC is supported
} else {
  // Use a fallback
}
if (Hls.WEBRTC_SUPPORT) {
  // WebRTC is supported
} else {
  // Use a fallback
}

实例化与参数配置

var hls = new Hls({p2pConfig: [opts]});

创建一个新的Hls实例。

var engine = hls.p2pEngine;

Hls 实例中获取 P2PEngine 实例。

如果指定了 opts ,那么对应的默认值将会被覆盖。

字段类型默认值描述
logLevelstring|boolean'error'log的等级,分为'warn'、'error'、'none',设为true等于'warn',设为false等于'none'。
tokenstringundefinedtoken用于控制台多域名数据汇总展示,另外如果自定义channelId也需要设置token。
livebooleantrue设置直播或者点播模式,不同模式会自动设置不同的hls.js参数。
trackerZonestring'eu'tracker服务器地址的国家代号,分为'eu'、'hk'、'us'。
memoryCacheLimitObject{"pc": 400 * 1024 * 1024, "mobile": 100 * 1024 * 1024}p2p缓存的最大数据量,分为PC和mobile。
p2pEnabledbooleantrue是否开启P2P。
webRTCConfigObject{}用于配置stun和datachannel的字典
useHttpRangebooleantrue在可能的情况下使用Http Range请求来补足p2p下载超时的剩余部分数据。
waitForPeerbooleanfalse优先尝试从对等端下载前几片数据,可以提高P2P比例,但可能会增加起播延时。
waitForPeerTimeoutnumber4.5waitForPeer的超时时间(单位秒),超时后恢复从http下载。
httpLoadTimenumber2.0P2P下载超时后留给HTTP下载的时间。
sharePlaylistbooleanfalse是否允许m3u8文件的P2P传输。
geoIpPreflightbooleantrue向在线IP数据库请求ASN等信息,从而获得更准确的调度,会延迟P2P启动时间。

P2PEngine API

P2PEngine.version (static)

获取 P2PEngine 的版本号。

P2PEngine.protocolVersion (static)

获取 P2P 协议的版本号,与其他平台互通的前提是 P2P 协议版本号相同。

P2PEngine.isSupported() (static method)

判断当前浏览器是否支持WebRTC data channel。

var engine = new P2PEngine(hlsjs, p2pConfig);

实例化 P2PEngine。也可以从 Hls 实例获取 P2PEngine 实例:

javascript
var hls = new Hls();
var engine = hls.p2pEngine;
var hls = new Hls();
var engine = hls.p2pEngine;

engine.enableP2P()

在p2p暂停或未启动情况下启动p2p。

engine.disableP2P()

停止p2p并释放内存。

engine.destroy()

停止p2p、销毁engine并释放内存。在Hls.js销毁时会自动调用。

P2PEngine事件

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信息

javascript
p2pConfig: {
    getStats: function (totalP2PDownloaded, totalP2PUploaded, totalHTTPDownloaded, p2pDownloadSpeed) {
        // 获取p2p下载信息
    },
    getPeerId: function (peerId) {
        // 获取本节点的Id
    },
    getPeersInfo: function (peers) {
        // 获取成功连接的节点的信息
    }
}
p2pConfig: {
    getStats: function (totalP2PDownloaded, totalP2PUploaded, totalHTTPDownloaded, p2pDownloadSpeed) {
        // 获取p2p下载信息
    },
    getPeerId: function (peerId) {
        // 获取本节点的Id
    },
    getPeersInfo: function (peers) {
        // 获取成功连接的节点的信息
    }
}

高级用法

解决动态m3u8路径问题

某些流媒体提供商的m3u8是动态生成的,不同节点的m3u8地址不一样,例如example.com/clientId1/streamId.m3u8和example.com/clientId2/streamId.m3u8,而本插件默认使用m3u8地址(去掉查询参数)作为channelId。这时候就要构造一个共同的chanelId,使实际观看同一直播/视频的节点处在相同频道中。

javascript
// 必须先在 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
}
// 必须先在 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。

javascript
p2pConfig: {
    token: YOUR_TOKEN,
    channelId: function (m3u8Url) {
        var parts = m3u8Url.split('/');
        var videoId = parts[parts.length-2]+'/'+parts[parts.length-1];
        return videoId;
    }
}
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
<!-- URL to be replaced -->
http://example.com/token123456/video1/playlist.m3u8

<!-- Resulting channelId -->
video1/playlist.m3u8

WARNING

如果要与其他平台互通,则必须确保两者拥有相同的 token 和 channelId 。

解决动态ts路径问题

类似动态m3u8路径问题,相同ts文件的路径也可能有差异,这时候需要忽略ts路径差异的部分。插件默认用ts的绝地路径(url)来标识每个ts文件,所以需要通过钩子函数重新构造标识符。可以按如下设置:

javascript
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;
    }
}
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优先策略

由于建立P2P连接需要时间,默认情况下前几片用HTTP下载。可以通过配置参数,等待P2P建立连接后优先用P2P下载,从而提升P2P效果,但可能会带来延时,建议在热度比较大的频道开启。

javascript
p2pConfig: {
    waitForPeer: true,
    waitForPeerTimeout: 4.5,     // 可以根据具体场景设置超时时间
}
p2pConfig: {
    waitForPeer: true,
    waitForPeerTimeout: 4.5,     // 可以根据具体场景设置超时时间
}

WARNING

暂不支持多码率HLS。

允许Http Range请求

当对等端上行带宽不够时,可能导致p2p传输超时而转向http下载,原本p2p下载的数据无法复用。Http Range请求用于补足p2p下载超时的剩余部分数据,要开启Http Range,首先需要源服务器支持,请参考允许Http Range请求,然后增加以下配置:

javascript
p2pConfig: {
    useHttpRange: true,
}
p2pConfig: {
    useHttpRange: true,
}

自行配置 STUN 和 TURN 服务器地址

STUN用于p2p连接过程中获取公网IP地址,TURN则可以在p2p连接不通时用于中转数据。本SDK已内置公开的STUN服务,开发者可以通过P2pConfig来更换STUN地址。TURN服务器则需要开发者自行搭建,可以参考coturn

javascript
p2pConfig: {
    webRTCConfig: {
       iceServers: [
           { urls: YOUR_STUN_OR_TURN_SERVER }
       ]
    }
}
p2pConfig: {
    webRTCConfig: {
       iceServers: [
           { urls: YOUR_STUN_OR_TURN_SERVER }
       ]
    }
}

切片合法性校验

有时候我们需要校验从节点下载的切片的合法性(类似bittorrent的哈希校验)。 CDNBye提供了一个钩子函数,可以回调下载的切片供开发者进行校验。用于校验的 哈希表建议直接从服务器下载,开发者可以通过程序计算每个ts文件的哈希并存储于 特定的文件中或者直接嵌入到m3u8文件中。如果校验失败,直接在回调函数中 返回false即可。

javascript
p2pConfig: {
   validateSegment: function (segId, buffer) {
       var hash = hashFile.getHash(segId);
       return hash === md5(buffer);
   }
}
p2pConfig: {
   validateSegment: function (segId, buffer) {
       var hash = hashFile.getHash(segId);
       return hash === md5(buffer);
   }
}

粤ICP备18075581号