Ztream

Ztream is a proof of concept for P2P-assisted Web music streaming built with WebRTC, Media Source API, AngularJS, Play Framework (Scala) and ReactiveMongo.
Streaming is performed by a combination of client-server access and P2P protocol between Web users. This is done in an adaptive and transparent way in order to reduce server bandwidth costs while ensuring low latency and smooth playback for users.

It is inspired from the architecture of the Spotify's desktop client, but highly simplified and transposed to the Web!

Works well in Chrome M30 (Chrome M31+ introduced some changes in Media source API + WebRTC data channels, and I haven't updated yet).

-> LIVE DEMO <-

How it works

Each peer (Web client) has 2 Websocket connections to the server: a control connection and a streaming binary connection. The control connection is used to handle all the control messages including the WebRTC's offer/answer messages.
An user can request to the server a series of chunks of the track he wants via the stream connection.

Here is what a peer does when his user chooses a track to listen to:

  1. If the track is in his local cache, he just plays it from there
  2. Otherwise, he will ask the server for the first chunks of the track (equivalent to ~10s) so that the playback can begin instantly (as the server is fast)
  3. In the meantime, the client asks the tracker to find a peer that has this track
  4. The tracker asks the last 20 peers that have entirely streamed the track if they can stream it (a peer can not stream to more than 2 other peers). The first to respond positively to the server (= the seeder) is selected and its id is sent back the the inital peer (= the leecher).
  5. A WebRTC PeerConnection is made between the leecher and the seeder, and the leecher can start streaming chunks of the track from the seeder via a binary DataChannel.
  6. At any time, if there is only around 4 seconds left in the playback buffer, the leecher stops streaming from the seeder (if there is any) and asks the server the next chunks of the track. This is a kind of emergency mode that occurs when no seeder is found or when the seeder is streaming too slowly. After receiving these new chunks, the leecher starts again streaming from the seeder or keeps on searching for one.

Moreover, on the server-side, upon a stream request of an user (random access from chunk x to chunk y of a track), the server streams the requested series of chunks directly from MongoDB GridFS and redirects this stream towards the client's Websocket, so that there is never an accumulation of chunks in the server memory (back-pressure is preserved). ReactiveMongo and its use of Play's Iteratee/Enumerator allows to get a stream from Mongo and to compose/transform it with a few lines of code.

Check the code for more details!

Note on audio format: Media Source currently only supports webm files (put in a html video element even for audio). You can easily convert your music to webm via ffmpeg: ffmpeg -i music.ogg -strict -2 music.webm

Ideas

  • For now, streamed tracks are cached in-memory on the client side (not a problem as the client can only stream one track in the demo). But for a multi-tracks Web client, the tracks should be cached in the FileSystem API instead of in-memory in order to have a persistent cache and more space.

  • Build a P2P overlay between peers in order to enable lookup requests without using the tracker (like in Spotify).

  • Instead of proposing tracks from Mongo, tracks (chunks) may be directly streamed by the server from services like SoundCloud, making Ztream a proxy to reduce streaming server bandwidth costs by orchestrating P2P communication between clients. If needed, re-encoding could be done on the fly via ffmpeg thanks to playCLI API that allows to transform Linux pipes into Enumeratee!

Feel free to fork and experiment =)



Ztream

Ztream是通过 WebRTC 构建的 P2P辅助Web音乐流的概念证明,媒体源API AngularJS Play Framework (Scala)和 ReactiveMongo
通过Web用户之间的客户端 - 服务器访问和P2P协议的组合来执行流。这是在一个 自适应和透明的方式,以便降低服务器带宽成本,同时确保用户的低延迟和平滑播放。

灵感来自Spotify桌面客户端的架构,但是 简化并转换到Web!

在Chrome M30中运行良好(Chrome M31 +在媒体源API + WebRTC数据通道中引入了一些更改,我还没有更新)。

- &gt; LIVE DEMO&lt; - -

工作原理

每个对等体(Web客户端)具有到服务器的两个Websocket连接:一个控制连接和一个流式二进制连接。控制连接用于处理所有控制消息,包括WebRTC的报价/答复信息 用户可以通过流连接向服务器请求一系列他想要的磁道块。

这是当他的用户选择一个音轨来聆听时,他们做了什么:

  1. If the track is in his local cache, he just plays it from there
  2. Otherwise, he will ask the server for the first chunks of the track (equivalent to ~10s) so that the playback can begin instantly (as the server is fast)
  3. In the meantime, the client asks the tracker to find a peer that has this track
  4. The tracker asks the last 20 peers that have entirely streamed the track if they can stream it (a peer can not stream to more than 2 other peers). The first to respond positively to the server (= the seeder) is selected and its id is sent back the the inital peer (= the leecher).
  5. A WebRTC PeerConnection is made between the leecher and the seeder, and the leecher can start streaming chunks of the track from the seeder via a binary DataChannel.
  6. At any time, if there is only around 4 seconds left in the playback buffer, the leecher stops streaming from the seeder (if there is any) and asks the server the next chunks of the track. This is a kind of emergency mode that occurs when no seeder is found or when the seeder is streaming too slowly. After receiving these new chunks, the leecher starts again streaming from the seeder or keeps on searching for one.
此外,在服务器端,在用户的流请求(从块x到轨道的块y的随机访问)中,服务器直接从MongoDB GridFS流式传送所请求的一系列块,并将该流重定向到客户端的Websocket,从而在服务器内存中不会有块的积累(背压保留)。 ReactiveMongo及其使用Play的Iteratee / Enumerator可以从Mongo获取流,并使用几行代码编写/转换它。

查看代码了解更多详情!

关于音频格式的注意事项:Media Source目前仅支持webm文件(甚至在音频中放入html视频元素)。您可以通过ffmpeg轻松将音乐转换为webm: ffmpeg -i music.ogg -strict -2 music.webm

想法

  • 现在,流式音轨在客户端缓存在内存中(不是问题,客户端只能在演示中流式传输一个音轨)。但是对于多轨Web客户端,轨道应该缓存在FileSystem API而不是内存中,以便具有持久缓存和更多空间。

  • 在对等体之间构建P2P覆盖,以便在不使用跟踪器的情况下启用查找请求(如Spotify)。

  • 而不是从Mongo提出曲目,服务器可以直接从SoundCloud等服务器流式传输(chunks),从而使Ztream成为一种代理,通过协调客户端之间的P2P通信来减少流服务器带宽成本。如果需要,可以通过ffmpeg进行重新编码,感谢 playCLI API ,允许将Linux管道转换为Enumeratee! / p>

自由分叉和实验=)




相关问题推荐