【问题标题】:Stream audio from client to server to client using WebSocket使用 WebSocket 将音频从客户端流式传输到服务器再到客户端
【发布时间】:2020-11-16 01:46:42
【问题描述】:

我正在尝试从客户端 Web 浏览器捕获麦克风音频,使用 WebSocket 将捕获的音频实时流式传输到 Node.js 服务器,然后再次将音频流式传输回不同的 Web 浏览器客户端。

到目前为止,在客户端,我在 JavaScript 中打开了一个 WebSocket 连接

const webSocket = new WebSocket('ws://127.0.0.1:8080');
webSocket.binaryType = 'blob';

在连接到服务器时,我从用户的麦克风捕获音频流,并在每 1 秒可用的每个可用数据块上,通过 WebSocket 将其发送到服务器

webSocket.onopen = event => {
console.log('info: connected to server');

navigator.mediaDevices
  .getUserMedia({ audio: true, video: false })
  .then(stream => {
    const mediaRecorder = new MediaRecorder(stream, {
      mimeType: 'audio/webm',
    });

    mediaRecorder.addEventListener('dataavailable', event => {
      if (event.data.size > 0) {
        webSocket.send(event.data);
      }
    });

    mediaRecorder.start(1000);
  });
};

现在,在服务器端,使用 ws 模块,我接收每个 blob 并将其发送到另一个客户端

wss.on('connection', ws => {
  console.log('info: client connected');

  ws.on('message', message => {
    wss.clients.forEach(client => {
      if (client !== ws && client.readyState === webSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

回到客户端,我尝试使用 audio 标签和引用 audioEl 播放音频

  webSocket.onmessage = event => {
    audioEl.src = window.URL.createObjectURL(event.data);
    audioEl.play();
  };

现在,我知道这仅适用于第一块数据(并且确实有效),因为audioEl.play(); 是异步的。在这种情况下,我尝试更改 audio 元素的 blob URL,每秒通过 WebSocket 接收到一个新 blob。

现在研究了一个星期后,我发现解决方案仅涉及如何将服务器流式传输到客户端音频、开始录制音频、停止录制然后将整个块作为 blob 发送。

我也尝试发送AudioBuffer,但不知道如何处理它以播放音频。

const context = new AudioContext();
    const source = context.createMediaStreamSource(stream);
    const processor = context.createScriptProcessor(1024, 1, 1);

    source.connect(processor);
    processor.connect(context.destination);

    processor.onaudioprocess = function(e) {
      webSocket.send(e.inputBuffer);
    }

我想要实现的是用户对着他/她的麦克风说话,音频直播流到服务器,然后流向另一个用户并同时播放。

如果我每秒发送一个 blob 的方法是正确的,我怎样才能使代码工作以连续播放音频?也许我需要创建一些我不知道的缓冲区。或者,如果方法完全不正确,请指导我使用正确的方法。

使用 WebRTC 技术进行点对点通信对我来说不是一个选择,因为我不想要 STUN 或 TURN 服务器的开销。

【问题讨论】:

  • 您的意思是,您更喜欢总是通过 websocket/TCP 服务器中继数据,而不是有时通过 TURN(udp;通常)服务器中继。重新考虑您的选择。

标签: javascript node.js websocket getusermedia web-mediarecorder


【解决方案1】:

MediaRecorder 将数据块传递给您的dataavailable 事件处理程序。为了使这些块有用,它们必须按顺序播放。它们是媒体文件的块,通常位于.webm format,也称为Matroska format。他们并不孤单。 (第一个除外)。

因此,如果您通过 websocket 有效负载将它们传递给另一个浏览器,它们确实无法单独播放。

您可以尝试在接收浏览器上解析 webm 文件,并设法从 websocket 的消息事件中播放它。有一个npm package called ebml 可以帮助解决这个问题。如果您寻求该解决方案,请查找“如何在浏览器中解码作品音频”。我已经为视频做了这个。开发和调试是 xxx 脖子上的痛。 (我这样做只是因为一些用户需要使用 Redmond Middle School Science Project(即 Microsoft Internet Explorer)来渲染低延迟视频。我本可以为所有这些用户购买新计算机,而开发它的成本是.)

WebRTC 通信堆栈打包音频的方式与 MediaRecorder 的方式截然不同,这很奇怪,但确实如此。

(值得一提的是,有一家名为 xirsys.com 的供应商提供 STUN/TURN 服务器。他们为开发和小批量工作提供了慷慨的免费层。这值得考虑。我在发展阶段,和他们在一起。)

【讨论】:

    猜你喜欢
    • 2014-01-19
    • 1970-01-01
    • 2010-10-17
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    相关资源
    最近更新 更多