Почему отваливается коннект websocket в связке JS-PHP при передаче звука с микрофона?

Пытаюсь посмотреть возможности передачи потоковых данных в режиме онлайн через вебсокеты. Для начала решил поэксперементировать только со звуком, т.е. реализовать подобие голосового чата. Т.к. наиболее близко знаком с PHP, на пощупать реализую сервер на этом языке с помощью Workerman. Суть проблемы: есть простейший код клиента на JS, который берёт поток с микрофона, режет его рекордером и отправляет серверу.

var socket = new WebSocket('ws://10.0.0.5:27801/');
    navigator.mediaDevices.getUserMedia({
        audio: true
    })
    .then(function(stream) {
      var $audio = document.getElementById("audio");
      var mediarecorder = new MediaRecorder(stream, {mimeType: "audio/webm; codecs=\"opus\""});
      // send
      mediarecorder.ondataavailable = function(e) {
        if (e.data && e.data.size > 0) {
          socket.send(e.data);
        }
      }
      mediarecorder.start(1000);
});

И есть простейший сервер на PHP, который просто отправляет полученные данные обратно.

<?php
include_once(__DIR__."/Workerman/Autoloader.php");

use Workerman\Lib\Timer;
use Workerman\Worker;

$worker = new Worker("websocket://0.0.0.0:27801");

$worker->onConnect = function($c){
    echo "Connected\n";
};

$worker->onMessage = function($c, $data){
    $c->send($data);
};

Worker::runAll();

Так вот если таким подходом отправлять текст, то всё ок. Но в описаной выше ситуации коннект на js просто отваливается при передаче данных с ошибкой в строке коннекта

WebSocket connection to 'ws://10.0.0.5:27801/' failed: Could not decode a text frame as UTF-8.

Нагуглить решение не удалось, менять тип коннекта на сервере пробовал. Что в данной ситуации пошло не так?


Ответы (1 шт):

Автор решения: Устьянцев Борис

Посмотрел ваш пример. Проблема здесь возникает из-за типа фрейма у вебсокета. Workerman по умолчанию посылает текстовый фрейм. JS видим что фрейм текстовый и ждёт что все символы будут в UTF-8. Не знаю как его правильно поменять в Workerman. Сходу не нашёл в документации. Получилось сделать так:

$worker->onMessage = function($c, $data){
    $c->websocketType = \Workerman\Protocols\Websocket::BINARY_TYPE_ARRAYBUFFER;
    $c->send($data);
};

Подсмотрел параметр соответственно в Websocket::encode(), через который пропускаются отправляемые данные. О чём написано в документации.

→ Ссылка