JavaScript reproduz arraybuffer como áudio. Precisa de ajuda para resolver "decodeaudiodata incapaz de decodificar dados de áudio"

Nov 02 2020

Eu tenho um servidor WebSocket .net core que recebe stream de áudio ao vivo do cliente A, então preciso transmitir esse áudio ao vivo para o cliente B (navegador). Portanto, recebi a matriz de bytes do cliente A e enviei a matriz de bytes para o cliente B (navegador) * A matriz de bytes está correta, pois posso convertê-la em .wav e reproduzi-la sem problemas.

No cliente B (navegador), tento decodificar o buffer de array no buffer de áudio para que possa ser colocado na saída e reproduzido.

O mediastreamhandler.SendArraySegToAllAsync é onde eu começo a enviar a matriz de bytes do servidor para o cliente B. Eu uso para enviar para todos os métodos primeiro, mais tarde será modificado e enviará os dados combinando o ID de conexão do websocket.

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);
        }

Em seguida, recebo a matriz de bytes de áudio por meio de websocket.onmessage em Javascript. Em seguida, passo a matriz de bytes para decodificar e reproduzir. Mas aqui diz "incapaz de decodificar os dados". Enquanto no Mozilla, dizia que o formato do conteúdo era desconhecido (preciso reformatar a matriz de bytes que recebo?) A matriz de bytes em si é adequada porque usei o mesmo byte para criar o arquivo .wav localmente e reproduzi-lo sem algum problema.

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();

    }

Em seguida, tento outro método para decodificar e reproduzir o áudio, desta vez, ele reproduziu alguns sons de ruído branco em vez de transmitir o áudio do Cliente 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();

    }

Eu acho que realmente preciso de alguma ajuda aqui, pessoal, tentando jogar o buffer de array em semanas e ainda assim, não poderia ter nenhum avanço. Preso aqui. Não tenho certeza do que fiz, vocês poderiam gentilmente me orientar ou me dizer alguma outra abordagem para isso? Muito obrigado antecipadamente, realmente sério.

Respostas

1 AnthumChris Nov 02 2020 at 02:43

decodeAudioData()requer arquivos completos, portanto, não pode ser usado para decodificar pedaços parciais de dados conforme são recebidos de um websocket. Se você pode transmitir arquivos de áudio Opus em seu websocket, você pode reproduzir com um decodificador WebAssembly disponível. Ver:

  • https://fetch-stream-audio.anthum.com/
  • https://github.com/AnthumChris/fetch-stream-audio
J.J Jan 18 2021 at 12:46

Resolvi o problema meses atrás, apenas aqui para postar minha solução.

Passos:

  1. O servidor recebe a string de carga útil do Twilio
  2. Envie a string de carga útil do servidor para o cliente (navegador).
 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);
 }
  1. Adicione wavheader à string de carga no lado do cliente antes de reproduzir o áudio.
function playSound(payloadBase64) {

     /* You can generate the wav header here --> https://codepen.io/mxfh/pen/mWLMrJ */
     var Base64wavheader = "UklGRgAAAABXQVZFZm10IBIAAAAHAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAAAAAABkYXRh";

     var audio = new Audio('data:audio/wav;base64,' + Base64wavheader + payloadBase64);
     audio.play();
};