使用低延迟且无中断的WebSocket传输音频流

3
我正在开发一个项目,需要从网页流式传输音频到其他客户端的能力。我已经在使用websocket,并希望将数据通道化。
我的当前方法使用Media Recorder,但是存在采样问题会导致中断。它会注册1秒音频,然后将其发送到服务器,再转发给其他客户端。有没有一种方法可以捕获连续的音频流并将其转换为base64?
也许如果有一种方法可以从MediaStream创建无延迟的base64音频,这将解决问题。你怎么看?
我想继续使用websocket,我知道有webrtc。你做过类似的事情吗?这可行吗?
                                                                --> Device 1
 MediaStream -> MediaRecorder -> base64 -> WebSocket -> Server --> Device ..
                                                                --> Device 18

这是当前方法的演示...你可以在此处尝试:https://jsfiddle.net/8qhvrcbz/
var sendAudio = function(b64) {
  var message = 'var audio = document.createElement(\'audio\');';
  message += 'audio.src = "' + b64 + '";';
  message += 'audio.play().catch(console.error);';
  eval(message);
  console.log(b64);
}

 navigator.mediaDevices.getUserMedia({
      audio: true
 }).then(function(stream) {
        setInterval(function() {
            var chunks = [];
            var recorder = new MediaRecorder(stream);
            recorder.ondataavailable = function(e) {
                chunks.push(e.data);
            };
            recorder.onstop = function(e) {
                var audioBlob = new Blob(chunks);
                var reader = new FileReader();
                reader.readAsDataURL(audioBlob);
                reader.onloadend = function() {
                    var b64 = reader.result
                    b64 = b64.replace('application/octet-stream', 'audio/mpeg');
                    sendAudio(b64);
                }
            }
            recorder.start();
            setTimeout(function() {
                recorder.stop();
            }, 1050);
        }, 1000);
    });

1
旁注:为什么使用Base64?WebSockets支持二进制数据。保存编码/解码将节省CPU和带宽。 - Myst
用base64进行测试更容易,我试过二进制但是没有太大的改善。 - BrainStack
@Myst 我认为问题出在MediaRecorder上,而不是数据本身,即使没有涉及到Websockets,它也会跳过。或者可能是播放器延迟的原因。我制作了一个使用blob而不是base64的小工具 https://jsfiddle.net/StarStep/0cqm56rz/4/ - BrainStack
1
为什么要使用Web Sockets?使用WebRTC,它有一个专门设计用于低延迟的整个堆栈。不要重复造轮子。 - Brad
我刚刚2分钟前发布了相同的答案。但是,WebRTC似乎更好地处理音频。我想使用websocket,因为它更容易将数据发送到多个客户端,并将工作卸载到服务器上。使用WebRTC,我们正在使用更多的连接...要进行测试。 - BrainStack
可能有一种方法可以在服务器上创建一个中间件来中继数据,但目前将坚持基本原则。 - BrainStack
2个回答

1

Websocket并不是最好的选择。我使用WebRTC代替websocket解决了这个问题。 在使用websocket时,记录时间为1050毫秒而不是1000毫秒,会导致一些重叠,但仍然比听到空白声音要好。


1
尽管您已经通过WebRTC解决了这个问题,这是行业推荐的方法,但我想分享我的答案。
问题不在于一般的websockets,而是MediaRecorder API。可以使用PCM音频捕获,然后将捕获的数组缓冲区提交到Web Worker或WASM进行编码为MP3块或类似格式。
const context = new AudioContext();
let leftChannel = [];
let rightChannel = [];
let recordingLength = null;
let bufferSize = 512;
let sampleRate = context.sampleRate;

const audioSource = context.createMediaStreamSource(audioStream);
const scriptNode = context.createScriptProcessor(bufferSize, 1, 1);

audioSource.connect(scriptNode);
scriptNode.connect(context.destination);
scriptNode.onaudioprocess = function(e) {
    // Do something with the data, e.g. convert it to WAV or MP3
};

根据我的实验,这将为您提供“实时”音频。我对MediaRecorder API的理论是,在发出任何导致可观延迟的内容之前,它会先进行一些缓冲。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接