JavaScript将arraybuffer作为音频播放。需要帮助解决 "decodeaudiodata无法解码音频数据"

1 人关注

我有一个.net core WebSocket服务器,它从客户端A接收实时流音频,然后我需要把这个实时音频流给客户端B(浏览器)。所以我从客户端A收到了字节数组,我把字节数组发送到客户端B(浏览器)*字节数组是正确的,因为我可以把它转换成.wav并顺利播放。

在客户端B(Browser)中,我试图将阵列缓冲区解码为音频缓冲区,以便将其放入输出并播放。

mediastreamhandler.SendArraySegToAllAsync是我开始从服务器向客户端B发送字节数组的地方。我首先使用发送至所有的方法,随后将进行修改,并通过匹配websocket连接ID发送数据。

private async Task Echo(HttpContext context, WebSocket webSocket)
            Debug.WriteLine("Start Echo between Websocket server & client");
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
                await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                await mediastreamhandler.SendArraySegToAllAsync(new ArraySegment<byte>(buffer, 0, result.Count));
            Debug.WriteLine("Close Echo");
            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);

然后我通过Javascript中的websocket.onmessage接收音频字节数组。然后我把字节数组传递给解码和播放。但在这里它说 "无法解码数据"。而在Mozilla中,它确实说内容格式未知(我需要重新格式化我收到的字节数组吗?)字节数组本身是好的,因为我已经用同样的字节数在本地创建了.wav文件并播放它,没有任何问题。

var ctx = new AudioContext();
    function playSound(arrBuff) {
        var myAudioBuffer;
        var src = ctx.createBufferSource();
        ctx.decodeAudioData(arrBuff, function (buffer) {
            myAudioBuffer = buffer;
        src.buffer = myAudioBuffer;
        src.connect(ctx.destination);
        src.start();

然后我尝试用另一种方法来解码和播放音频,这一次,它播放了一些白噪声,而不是从客户端A流出来的音频。

var ctx = new AudioContext();
    function playSound(arrBuff) {
        var myAudioBuffer;
        var src = ctx.createBufferSource();
        myAudioBuffer = ctx.createBuffer(1, arrBuff.byteLength, 8000);
        var nowBuffering = myAudioBuffer.getChannelData(0);
        for (var i = 0; i < arrBuff.byteLength; i++) {
            nowBuffering[i] = arrBuff[i];
        src.buffer = myAudioBuffer;
        src.connect(ctx.destination);
        src.start();

我想我真的需要一些帮助,试图在几周内打出阵列缓冲区,但仍然无法有任何突破。困在这里了。我不知道我做了什么,你们能指导我或告诉我任何其他的方法吗?非常感谢,真的很感谢。

7 个评论
Brad
你不能以这种方式可靠地传输音频。 你将会在你的音频中出现空白和跳过。 有点关系: stackoverflow.com/a/64040169/362536 跳过网络套接字路线,直接通过HTTP流。 或者,如果延迟很重要,就实施WebRTC。
J.J
嗨,布拉德,谢谢你的指导。但是我的客户使用Twilio服务,而Twilio服务需要websocket来发送实时音频。真的不能跳过网络套接字路线。
J.J
我需要从websocket解码块状数据并在浏览器中播放。或者在发送给浏览器之前,先将数据处理成 "完整的 "字节数组,这样decodeAudioData()才能真正 "理解 "字节数组。
我目前在使用Twilio媒体流时面临这个问题,你是如何解决的?我想直接从经纪商那里收听通话的音频流。
J.J
嗨,Tayomi,我通过从服务器向客户端发送字符串有效载荷来解决这个问题。然后在播放音频之前,在有效载荷中添加wavheader。
J.J
function playSound(payloadBase64) { var Base64wavheader = "UklGRgAAAABXQVZFZm10IBIAAAAHAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAABkYXRh"; var audio = new Audio('data:audio/wav;base64,' + Base64wavheader + payloadBase64); audio.play(); }。
J.J
你可以在这里生成你的wavheader,只要记得相应地调整通道、采样率和比特。 codepen.io/mxfh/pen/mWLMrJ
javascript
websocket
audio-streaming
web-audio-api
audiobuffer
J.J
J.J
发布于 2020-11-02
2 个回答
AnthumChris
AnthumChris
发布于 2021-01-18
已采纳
0 人赞同

decodeAudioData() 需要完整的文件,所以它不能用来解码从websocket接收的部分数据块。 如果你能在你的websocket上流传Opus音频文件,你可以用一个可用的WebAssembly解码器来播放。 见。

  • https://fetch-stream-audio.anthum.com/
  • https://github.com/AnthumChris/fetch-stream-audio
  • J.J
    谢谢你的源代码,我会看看的! :D 只是一个简单的问题,你的例子是否包括将websocket的部分数据块解码成音频? 还是将字节数组处理成 "完整 "的数据,然后再发送到decodeAudioData()进行解码。
    这个例子没有使用websockets,但你可以从看到该代码的工作方式中推导出websocket的实现。 请看 README 中关于 decodeAudioData() 的内容。
    J.J
    谢谢你,你的榜样确实为我指引了正确的道路。
    J.J
    J.J
    发布于 2021-01-18
    0 人赞同

    我几个月前就已经解决了这个问题,只是在这里公布我的解决方案。

  • 服务器从Twilio接收有效载荷字符串
  • 从服务器向客户端(浏览器)发送有效载荷字符串。
  •  public async Task SendMessageAsync(WebSocket socket, string message)
         if (socket.State != WebSocketState.Open)
             return;
         await socket.SendAsync(buffer: new ArraySegment<byte>(array: Encoding.ASCII.GetBytes(message),
                                                                      offset: 0,
                                                                      count: message.Length),
                                       messageType: WebSocketMessageType.Text,
                                       endOfMessage: true,
                                       cancellationToken: CancellationToken.None);
    
  • 在播放音频之前,在客户端的有效载荷字符串中添加wavheader。
  • function playSound(payloadBase64) {
         /* You can generate the wav header here --> https://codepen.io/mxfh/pen/mWLMrJ */
    var Base64wavheader = "UklGRgAAAABXQVZFZm10IBIAAAAHAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAAAAAABkYXRh";