Как синхронизировать музыкальный проигрыватель с несколькими клиентами в NodeJS - PullRequest
0 голосов
/ 18 мая 2019

Я написал скрипт для базовой синхронизации песни с несколькими клиентами. Проблема в том, что клиент 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();
});

В общем, мне нужна помощь в том, как я должен позволить им работать ровно в одно и то же время.

Заранее спасибо.

1 Ответ

1 голос
/ 19 мая 2019

Первое, что вам нужно сделать, это настроить канал связи между двумя клиентами, которые будут синхронизированы. Учитывая ваши требования к задержке, я предполагаю, что эти клиенты физически находятся рядом друг с другом и, вероятно, находятся в одной сети. В этом случае вам будет полезно создать одноранговое соединение WebRTC с каналом передачи данных между ними. Как правило, клиенты могут договариваться о соединении через сеть, к которой они совместно, вместо того, чтобы отправлять данные на сервер и обратно, что уменьшает задержку этого канала данных.

Далее, буферизируйте носитель, как обычно. Вы можете использовать .buffered, чтобы определить, какие временные диапазоны были буферизованы. Как правило, вы можете положиться на событие canplaythrough , чтобы определить, достаточно ли у игрока буферизовано, чтобы играть без необходимости повторного буфера.

Затем решите, какой конец будет «основным», откуда будут поступать все данные синхронизации. Начните воспроизведение с обеих сторон.

Регулярно, когда воспроизведение продолжается, мастер должен отправить свои currentTime другим клиентам. Получив эти клиенты, они должны проверить свои currentTime, чтобы узнать, как далеко они находятся. Оттуда они должны сделать расчет относительно того, как наверстать упущенное. Например, если ведущий находится на 100.100, а подчиненный клиент на 100.000, то он должен составлять 100 миллисекунд. Если вы установите playbackRate на 1.01, это время будет превышать 10 секунд. Или 1.02, и вы сделаете это за 5 секунд.

Вы захотите придумать формулу, которая определяет серьезность десинхронизации и облегчает ее исправление. Вам также понадобятся некоторые разумные ограничения на эту скорость воспроизведения. (Например, вы, вероятно, не хотите идти быстрее / медленнее для синхронизации более, чем на 10%.) Кроме того, если они достаточно плохо разделены, вы можете приостановить один, установите currentTime для другого ( который обычно вызывает некоторое отклонение) и начинается снова.

Улучшение, которое вы можете сделать, - это также определить задержку между ведущим / ведомым. Если мастер говорит: «Сейчас 12,345 с», а спустя 100 миллисекунд вы получите эту метку времени, то на самом деле это 12,445. Вы можете реализовать «пинг», когда задержка постоянно измеряется. А еще лучше добавьте это в каждое сообщение о времени.

Это должно помочь вам приблизиться по времени, достаточное для большинства случаев использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...