Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: live streaming #1993

Open
dmlap opened this issue Jan 28, 2021 · 14 comments
Open

Proposal: live streaming #1993

dmlap opened this issue Jan 28, 2021 · 14 comments

Comments

@dmlap
Copy link

dmlap commented Jan 28, 2021

The BitTorrent protocol assumes that files in a torrent are known ahead of time. That makes BitTorrent (and consequently, WebTorrent) difficult to use with live media. Workarounds exist ("Is it possible to do live streaming with WebTorrent?", for instance) but they have substantial drawbacks – torrents are either at a signficant delay or the timeframe for peers to assist in delivery is very limited. Live streaming could benefit enormously from a robust peer-assisted model. Live events are unpredictable and traditional scaling mechanisms aren't designed for usage to spike by a factor of a million in the span of a few minutes. WebTorrent could flip that on its head and make live streaming more reliable as audiences surge.

The goal of this proposal is to enhance conventional live streaming with P2P. WebTorrent uses the BitTorrent protocol because it's already proven and hugely successful. The idea here is similar: use the best parts of the BitTorrent and live streaming ecosystem so that it's easy for existing, battle-tested clients and tools to adopt. Just like WebTorrent, it's probably necessary for some client changes but to keep them to an absolute minimum.

Proposal

Peers distribute content by exchanging request and piece messages in the peer protocol. Requests specify a piece index, a byte offset, and a length. Torrents created from the traditional metadata assign piece indices sequentially based on file declaration order. From the perspective of the peer protocol, however, a piece index is just a number. If we reinterpret that number as a piece identifier (and relax some constraints about piece density), existing peer behavior starts looking applicable to a lot more scenarios. More concretely, here are my proposed modifications to WebTorrent to support live delivery:

  • Interpret pieceIndex as an identifier. The composition of that identifier could be left up to implementations but using existing live video formats to inform the choice seems likely to play better with piece-selection algorithms like sequential downloading. I've built a PoC that uses 1 reserved bit, 8 bits for a stream identifier (aka "rendition"), 32 bits for a media segment number, and 12 bits for a piece index within that segment. It's 53-bits total so that it fits within the exact integer arithmetic range for Javascript and the fields are ordered so that if you're interested in piece N, you're likely interested in piece N + 1.
  • Use sparse representations (like Map or sparse-chunk-store) for torrent.bitfield, torrent.pieces, torrent._store, torrent._hashes, and wire.peerPieces.
  • Don't bother sending bitfield messages for live streaming torrents, rely on have messages instead.
  • Add a method to register new files. Existing video player libraries can use manifest-polling or any other existing method to discover new media segments and feed that info to WebTorrent as the stream progresses.

With those modifications in place, if you're a live streamer you would:

  1. Create a standard HLS or DASH live video stream. Bonus points if you lay things out sanely so your HTTP endpoints can be used as a web seed directly.
  2. Add metadata to your manifests specifying their length in bytes and the concatenation of the SHA-1 hash of every 2^18 bytes. Pad the last piece with zeroes for the purposes of calculating the final SHA-1, if necessary.
  3. Publish the annotated manifest.

A client/video player would then:

  1. Fetch the HLS or DASH manifest as normally.
  2. Parse out the segments and associated BitTorrent metadata.
  3. Register and fetch those segment files with WebTorrent. Under the covers, WebTorrent could fetch them from the web seed or peers that are available. WebTorrent already has prioritization mechanisms so the player's segment fetching logic could retain priority.
  4. Buffer segments as they are received.

The steps in bold are different than the typical live streaming setup today. I've put together some tooling to help with manifest annotation and I believe most video players have extension hooks that could be used to add in the new client behavior.

@dmlap
Copy link
Author

dmlap commented Jan 28, 2021

I've built a proof-of-concept by patching bits of WebTorrent at runtime. I'd like to put together a public demo and I'm working out how to do it without running a 24/7 live stream myself. The PoC seems to work reasonably well as a runtime patch but I think it would be ideal if this capability were a first-class citizen for WebTorrent. I'd appreciate any thoughts on this proposal (or, certainly, interest in a PR). Thanks!

@ThaUnknown
Copy link
Member

ThaUnknown commented Mar 2, 2021

there is something similar to what you're describing called live-torrent but I'm not sure if this satisfies your needs since it requires a server script to make a HLS manifest with magnet links in it, and still has a bit of delay, and there was comeover but it has a solid 10-15 second delay but it's been down for quite some time, but from what I understand all those implementation have connection limits...

@snowinszu
Copy link
Contributor

For live streaming, cdnbye maybe better option: https://www.cdnbye.com/en/

@anesuc
Copy link

anesuc commented Mar 15, 2021

For live streaming, cdnbye maybe better option: https://www.cdnbye.com/en/

I've seen this recommended in some other thread here. Firstly does that have native support for live streaming? Secondly is that bandwidth charge across all the pears? Like for every new peer that joins and downloads also adds to the bandwidth? If so that's not a really good option imo because with live streams you'll hit those limits real quick

@anesuc
Copy link

anesuc commented Mar 15, 2021

I just realised this is your product/project. I think you should disclose that whenever suggesting it as a better option.

@resession
Copy link
Contributor

Streaming should be added to any type of file, like a constant stream like websocket

@ForestJohnson
Copy link

ForestJohnson commented Jan 4, 2022

So, I'm working on trying to figure this out as well with WebTorrent and based on what i'm seeing the easiest and most reasonable solution would be to simply make each video chunk (hls .ts file) into its own torrent.

By using a private tracker, getting rid of all the default 3rd party trackers in globalThis.WEBTORRENT_ANNOUNCE, and enabling trickle ICE on all WebTorrent peers involved (requires modifying the hardcoded trickle: false config in WebSocketTracker._createPeer), I was able to get the latency for starting a new torrent download down to about 250ms in my test environment.

However this is the problem I'm seeing now:

Torrents are immutable, can't add new content to them (new HLS segments) but also each torrent in webtorrent has to have its own swarm, and peer connections can't be shared between swarms AFAIK. So all the peers would have to reconnect for each HLS segment file. That would not be acceptable to reconnect the entire swarm every time a new segment comes out.

IMO the easiest way to do this might be to try to "lift" or "abstract" the peer connections out 1 layer away from the torrents themselves.. so that if peers Alice and Bob already negotiated a connection for the torrent of streeem_segment_1311.ts then they can re-use that same connection when streeem_segment_1312.ts rolls around.

I still have to do some more research and testing to figure this out. It would probably require me to build in support for a new type of metadata value that gets specified on the magnet link: something like swarmGroup, torrentGroup, or something. Basically an identifier that we can group peer connections by for re-use in multiple torrents / multiple "swarms".

So under this regime when peer Alice receives the magnet link of streeem_segment_1312.ts (receives it "out of band", the way it gets sent should be part of the stream-->webtorrent integration, not part of webtorrent IMO) then she will notice that it has the same torrentGroup, lets say, streeem-segmentz as some other active torrents that she has. Since she already has peer connections to peers Bob, Cathy, Daryl, and Eve in that torrentGroup, she will instantly join the new swarm for streeem_segment_1312.ts already connected to those 4 other peers.

This may require a multiplexing layer inside the webRTC DataChannels, I'm not sure. For now I will probably fork webtorrent and all of the related libraries in order to test this, assuming I ever manage to put the time aside to work on it.

@ThaUnknown
Copy link
Member

So, I'm working on trying to figure this out as well with WebTorrent and based on what i'm seeing the easiest and most reasonable solution would be to simply make each video chunk (hls .ts file) into its own torrent.

By using a private tracker, getting rid of all the default 3rd party trackers in globalThis.WEBTORRENT_ANNOUNCE, and enabling trickle ICE on all WebTorrent peers involved (requires modifying the hardcoded trickle: false config in WebSocketTracker._createPeer), I was able to get the latency for starting a new torrent download down to about 250ms in my test environment.

However this is the problem I'm seeing now:

Torrents are immutable, can't add new content to them (new HLS segments) but also each torrent in webtorrent has to have its own swarm, and peer connections can't be shared between swarms AFAIK. So all the peers would have to reconnect for each HLS segment file. That would not be acceptable to reconnect the entire swarm every time a new segment comes out.

IMO the easiest way to do this might be to try to "lift" or "abstract" the peer connections out 1 layer away from the torrents themselves.. so that if peers Alice and Bob already negotiated a connection for the torrent of streeem_segment_1311.ts then they can re-use that same connection when streeem_segment_1312.ts rolls around.

I still have to do some more research and testing to figure this out. It would probably require me to build in support for a new type of metadata value that gets specified on the magnet link: something like swarmGroup, torrentGroup, or something. Basically an identifier that we can group peer connections by for re-use in multiple torrents / multiple "swarms".

So under this regime when peer Alice receives the magnet link of streeem_segment_1312.ts (receives it "out of band", the way it gets sent should be part of the stream-->webtorrent integration, not part of webtorrent IMO) then she will notice that it has the same torrentGroup, lets say, streeem-segmentz as some other active torrents that she has. Since she already has peer connections to peers Bob, Cathy, Daryl, and Eve, she will instantly join the new swarm for streeem_segment_1312.ts already connected to those 4 other peers.

This may require a multiplexing layer inside the webRTC DataChannels, I'm not sure. For now I will probably fork webtorrent and all of the related libraries in order to test this, assuming I ever manage to put the time aside to work on it.

250ms is really optimistic, especially on lower end hardware, where a phone it can take up to 3-5s to even parse the torrent file, let alone resolve the torrent peers. I really don't think webtorrent is built for this, wrtc already provides a lot of good options which imho you should use instead

@ForestJohnson
Copy link

ForestJohnson commented Jan 4, 2022

on lower end hardware, where a phone it can take up to 3-5s to even parse the torrent file

Which lower end hardware? a nokia brick phone from the year 2000? Can you give a concrete example? I have a hard time believing that parsing the torrent metadata / index is anything more than trivial. You said it yourself:

there's very little to be gained from a WASM implementation, most performance in webtorrent is lost in transferring data from/to stores and peers

But you don't really know until you profile it. I'd love to see some profiler results for WebTorrent if you have them :) and I'll probably end up profiling it myself if/when I get into this.

wrtc already provides a lot of good options which imho you should use instead

Like which? I'm assuming by "wrtc" you mean webrtc in general? Are you talking about WebRTC video?

This isn't really about video, at least from my PoV this is about chunks of bytes, and how to distribute them to many consumers efficiently even when all the bytes/chunks can't be known in advance, i.e. they are "live".
I am investigating BitTorrent as an option for that. BitTorrent has been a rock solid technology which excels at distributing bytes for many many years. Who knows, maybe this experiment will fail or I will pivot to something else, thats why I'm making these posts, just trying to get more information.

@ThaUnknown
Copy link
Member

ThaUnknown commented Jan 4, 2022

Which lower end hardware? a nokia brick phone from the year 2000? Can you give a concrete example? I have a hard time believing that parsing the torrent metadata / index is anything more than trivial. You said it yourself:

Redmi note 8 pro, I know, it surprised me a lot too, I have no clue why, 90% of the time it just spends idle, I still to this day don't know where the issue lies

But you don't really know until you profile it. I'd love to see some profiler results for WebTorrent if you have them :) and I'll probably end up profiling it myself if/when I get into this.

This isn't very related, it's not that its CPU intensive, its that it takes time.

Like which? I'm assuming by "wrtc" you mean webrtc in general? Are you talking about WebRTC video?
Mainly video HLS on P2P is honestly asking for trouble

BT is nice for static content, but that's about where it ends since the protocol was designed to share static files, not stream unknown content, if you don't know the data beforehand, using BT for it is gonna be like re-inventing the circle, and there are a few issues with this, and a few reasons why p2p isn't used in livestreaming.

If you don't want this to scale, then you're 100% looking in the wrong place, since then you can just have the root peer distribute data to all other connections, or at most distribute it to most powerful peers which then offload a bit using generic WebRTC.

If you want this to scale close to infinitely like BT is designed to do, then I don't think web is the place to do it. In a perfect land every peer would have good enough hardware and connection to distribute to other peers, but that's rarely true. Especially for volatile data like this which is gonna be outdated in 30 seconds. Even if you had a few good powerful peers, determining which ones they are, will take time, especially for this, which means peers will very quickly desync, and once that happens they will need to skip past some "chunks" or in your case torrents. The only way to realistically fix this is to have a main root peer which can distribute data to peers if there are no stable connections, and at this point you're at square 1, aka why are you even using BT and not straight wrtc. This will only work reliably with 100's of viewers at which point you're hitting the limitations of WRTC, so transitioning cleanly between a static connection and a p2p swarm is needed.

This is something I have spent almost a year working on and with the current webtorrent structure you can't do reliably without absolutely demolishing UX, best way of doing it is to have low priority static webseeds, alongside the peers, but because of how webseeds are implemented in WT, even a single poor health peer will drop the webseeds speed to <600KB/s, even if your servers can handle 1000's of Gbit/s

@taylordwright44
Copy link

For live streaming, cdnbye maybe better option: https://www.cdnbye.com/en/

That costs money and we can't tinker with the code itself or host it on our own server. Judging by the fact that your avatar is literally their logo, it'd pretty obvious you're just advertising your own product. If I'm wrong and it's open source, by all means show please prove me wrong and post the repo for it.

@anesuc
Copy link

anesuc commented May 7, 2023

You can use https://github.com/Novage/p2p-media-loader which is what I started using for a while now. I think that paid service being advertised here is based on it.

@snowinszu
Copy link
Contributor

You can use https://github.com/Novage/p2p-media-loader which is what I started using for a while now. I think that paid service being advertised here is based on it.

Actually cdnbye is not based on p2p-media-loader, there are many advantage of paid service such as continuous maintenance, muiti-paltform supporting, and pay as you go :)

@anesuc
Copy link

anesuc commented May 26, 2023

You can use https://github.com/Novage/p2p-media-loader which is what I started using for a while now. I think that paid service being advertised here is based on it.

Actually cdnbye is not based on p2p-media-loader, there are many advantage of paid service such as continuous maintenance, muiti-paltform supporting, and pay as you go :)

Not diminishing your product, It probably is a decent service. However, the things you listed as benefits aren't exclusive to a paid product, some of which do not sound like a benefit. Open source options can also offer "continuous maintenance" (in fact this is considered one of the stronger reasons to go for such an option because you aren't relying on a company to still exist and offer updates to that product all the time - if company moves on to other products or goes bankrupt you are now stuck alone), multiplatform supporting - also not exclusive to a paid service, once again utilising community effort in an open source project resolves this (look at Linux for a strong example) and "pay as you go" does not sound like an advantage either unless if we were comparing to another paid service which we aren't.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants