Table of contents:
- What is tracker?
- Don't use public trackers in production
- How to achieve better P2P ratio for live streams?
- How to achieve better P2P ratio for VOD streams?
- What are the requirements to share a stream over P2P?
- Is it possible to have 100% P2P ratio?
- What happens if there are no peers on a stream?
- How to configure personal tracker and stun servers?
- How to manually set swarm ID?
- How to see that P2P is actually working?
- How to debug?
P2P Media Loader
uses WebTorrent compatible trackers to do WebRTC signaling - exchanging SDP data between peers to connect them into a swarm.
Few public trackers are configured in the library by default for easy development and testing but don't use public trackers in production.
Any compatible WebTorrent tracker works for P2P Media Loader
:
- Aquatic - A high-performance BitTorrent tracker written in Rust.
- wt-tracker - high-performance WebTorrent tracker by Novage that uses uWebSockets.js for I/O.
- bittorrent-tracker - tracker from WebTorrent project that uses Node.js I/O
Public trackers allow quickly begin development and testing of P2P technologies on the web. But they support a limited number of peers and can reject connections or even go down on a heavy loads.
That is why they can't be used in production environments. Consider running your personal tracker or buy resources from a tracker provider to go stable.
The requirements to share a stream over P2P are:
- The stream should have the same swarm ID on all the peers. Swarm ID is equal to the stream manifest URL without query parameters by default. If a stream URL is not the same for different peers you can set the swarm ID manually using configuration.
- The manifest should have the same number of variants (i.e. qualities) in the same order on all the peers. URLs of the variant playlists don't matter.
- Variants should consist of the same segments under the same sequence numbers (see #EXT-X-MEDIA-SEQUENCE for HLS) on all the peers. URLs of the segments don't matter.
It is possible for a single peer but not possible for a swarm of peers in total.
P2P Media Loader implements approach of P2P assisted video delivery. It means that the stream should be downloaded via HTTP(S) at least once to be shared between peers in a swarm.
For example for 10 peers in the best case the maximum possible P2P ratio is 90% if a stream was downloaded from the source only once.
P2P Media Loader downloads all the segments from HTTP(S) source in this case. It should not perform worse than a player configured without P2P at all.
const config = {
core: {
announceTrackers: [
"wss://personal.tracker1.com",
"wss://personal.tracker2.com",
],
rtcConfig: {
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "stun:global.stun.twilio.com:3478?transport=udp" },
],
},
},
};
const engineShaka = new ShakaP2PEngine(config, shaka);
// or
const engineHlsJs = new HlsJsP2PEngine(config);
const HlsWithP2P = HlsJsP2PEngine.injectMixin(Hls);
const hls = new HlsWithP2P({
p2p: {
core: {
announceTrackers: [
"wss://personal.tracker1.com",
"wss://personal.tracker2.com",
],
rtcConfig: {
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: "stun:global.stun.twilio.com:3478?transport=udp" },
],
},
},
onHlsJsCreated(hls) {
// Subscribe to P2P engine and Hls.js events here
hls.p2pEngine.addEventListener("onSegmentLoaded", (details) => {
console.log("Segment Loaded:", details);
});
},
},
});
const config = {
core: {
swarmId: "https://somecdn.com/mystream_12345.m3u8", // any unique string
},
};
const engineShaka = new ShakaP2PEngine(config, shaka);
// or
const engineHlsJs = new HlsJsP2PEngine(config);
const HlsWithP2P = HlsJsP2PEngine.injectMixin(Hls);
const hls = new HlsWithP2P({
p2p: {
core: {
swarmId: "https://somecdn.com/mystream_12345.m3u8", // any unique string
},
onHlsJsCreated(hls) {
// Subscribe to P2P engine and Hls.js events here
hls.p2pEngine.addEventListener("onSegmentLoaded", (details) => {
console.log("Segment Loaded:", details);
});
},
},
});
The easiest way is to subscribe to P2P events and log them:
const engine = new HlsJsP2PEngine();
engine.addEventListener("onSegmentLoaded", (details) => {
console.log("Segment Loaded:", details);
});
const HlsWithP2P = HlsJsP2PEngine.injectMixin(Hls);
const hls = new HlsWithP2P({
p2p: {
onHlsJsCreated(hls) {
hls.p2pEngine.addEventListener("onSegmentLoaded", (details) => {
console.log("Segment Loaded:", details);
});
},
},
});
Open few P2P enabled players with the same stream so they can connect.
To enable ALL debugging type in browser's console localStorage.debug = 'p2pml-core:*'
and reload the webpage.
To enable specific logs use filtering like localStorage.debug = 'p2pml-core:peer'
.
Check the source code for all the possible log types.