如何在 NodeJS 中将音乐播放器同步到多个客户端

How to synchronize a music player to multiple clients in NodeJS

我写了一个脚本,基本上可以将一首歌同步到多个客户端。问题是,客户 1 总是比客户 2 更深入歌曲。

当客户端1正在播放歌曲时,客户端2按下一个按钮,客户端1将当前时间发送给客户端2,以便客户端2可以获取时间并播放mp3。

我试过预加载mp3,这样客户端2就不会在歌曲开始时浪费时间加载文件。然而还是晚了+-0.5秒。

//客户端

$(document).ready(function() {
    var currentId = "";

    document.getElementById("audio").load();

    $.ajax({
        url: '/retrieveId',
        type: 'post',
        success: function(data) {
        currentId = data;
        console.log(currentId);
        }
    });


    $('#host').click(function () {
        $('#audio')[0].play();
        var interval2 = setInterval(function() {
            var currTime = document.getElementById('audio').currentTime;
            $.ajax({
            url: '/startedPlaying',
            type: 'post',
            data: { time: currTime, minute: '10' },
            success: function(data) {
            }
            });
        },10);
    });

    $('#client').click(function() {
    document.getElementById("audio").play();
        $.ajax({
            url: '/retrieveTime',
            type: 'post',
            success: function(data) {
                document.getElementById("audio").currentTime = data;
            }
        });
    })
});

//服务器

app.use(bodyParser.urlencoded({ extended: true }));

app.get("/", function(req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
}).listen(12340);


app.post("/startedPlaying", function(req, res) {
currTime = req.body.time;
res.end();
});

app.post("/retrieveTime", function(req, res) {
res.send(currTime);
res.end();
});

app.post("/retrieveId", function(req, res) {
id++;
res.send(id.toString());
res.end();
});

所以基本上,我需要有关如何让它们 运行 完全同时出现的帮助。

提前谢谢你。

您需要做的第一件事是在要同步的两个客户端之间建立一个通信通道。鉴于您的延迟要求,我猜测这些客户端在物理上彼此靠近并且可能位于同一网络上。在这种情况下,您将受益于在它们之间创建一个带有数据通道的 peer-to-peer WebRTC 连接。通常,客户端可以通过他们共享的网络协商连接,而不必将数据发送到服务器并返回,这减少了该数据通道的延迟。

接下来,像往常一样缓冲媒体。您可以使用 .buffered to determine what time ranges have been buffered. You can generally rely on the canplaythrough event 来确定播放器何时缓冲到足以播放而无需再次缓冲。

然后,决定"master"哪一端,所有同步数据都从哪里来。开始双面播放。

正常情况下,随着播放的进行,主机应该将其currentTime to the other clients. Upon receiving, those clients should check their own currentTime to see how far away they are. From there, they should make a calculation as to how to catch up. For example, if the master is at 100.100 and a slave client is at 100.000, then it needs to make up 100 milliseconds. If you set the playbackRate发送到1.01,你将在10秒内补上这个时间。或者,1.02,您将在 5 秒内完成。

您需要想出一些公式来确定不同步的严重程度并轻松修复它。您还需要对该播放速度进行一些合理的限制。 (例如,您可能不想同步 faster/slower 超过 10%。)此外,如果两者分离得足够严重,您可以选择暂停一个,设置 currentTime另一方面(这通常会导致一些重新缓冲)并重新开始。

您可以做的一项改进是还确定 master/slave 之间的延迟。如果主人说 "now is 12.345s",而你在 100 毫秒后收到,这个时间戳实际上是 12.445。您可以实现持续测量延迟的 "ping" 类型。更好的是,在每条定时消息上都加上这个。

这应该让您在时间上非常接近,足以满足大多数用例。