将实时音频流式传输到 Node.js 服务器

JCA*_*era 5 javascript audio node.js

我正在开发一个项目,需要将音频流发送到 Node.js 服务器。我可以使用此功能捕获麦克风声音:

function micCapture(){
    'use strict';

    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

    var constraints = {
        audio: true,
        video: false
    };

    var video = document.querySelector('video');

    function successCallback(stream) {
        window.stream = stream; // stream available to console
        if (window.URL) {
            video.src = window.webkitURL.createObjectURL(stream);
        } else {
            video.src = stream;
        }
        //Send audio stream
        //server.send(stream);
    }

    function errorCallback(error) {
        console.log('navigator.getUserMedia error: ', error);
    }

    navigator.getUserMedia(constraints, successCallback, errorCallback);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我能够捕获音频并在网站上播放。

现在我想将该音频流发送到 Node.js 服务器,并将其发送回其他客户端。就像语音聊天一样,但我不想使用 WebRTC,因为我需要服务器中的流。我怎样才能实现这个目标?我可以使用 socket.io-stream 来做到这一点吗?在我看到的示例中,他们录制了音频并发送了文件,但我需要“实时”音频。

Sis*_*sir 5

我最近使用 socket.io 从浏览器到服务器进行了实时音频上传。我将在这里回答,以防其他人需要。

    var stream;
    var socket = io();
    var bufferSize = 1024 * 16;
    var audioContext = new AudioContext();
    // createScriptProcessor is deprecated. Let me know if anyone find alternative
    var processor = audioContext.createScriptProcessor(bufferSize, 1, 1);
    processor.connect(audioContext.destination);

    navigator.mediaDevices.getUserMedia({ video: false, audio: true }).then(handleMicStream).catch(err => {
      console.log('error from getUserMedia', err);
    });

Run Code Online (Sandbox Code Playgroud)

handleMicStream当用户接受使用麦克风的权限时将运行。

  function handleMicStream(streamObj) {
    // keep the context in a global variable
    stream = streamObj;

    input = audioContext.createMediaStreamSource(stream);

    input.connect(processor);

    processor.onaudioprocess = e => {
      microphoneProcess(e); // receives data from microphone
    };
  }


  function microphoneProcess(e) {
    const left = e.inputBuffer.getChannelData(0); // get only one audio channel
    const left16 = convertFloat32ToInt16(left); // skip if you don't need this
    socket.emit('micBinaryStream', left16); // send to server via web socket
  }

// Converts data to BINARY16
function convertFloat32ToInt16(buffer) {
    let l = buffer.length;
    const buf = new Int16Array(l / 3);

    while (l--) {
      if (l % 3 === 0) {
        buf[l / 3] = buffer[l] * 0xFFFF;
      }
    }
    return buf.buffer;
  }



Run Code Online (Sandbox Code Playgroud)

让您的 socket.io 服务器监听micBinaryStream,您应该获取数据。我需要数据作为BINARY16google api 的格式,如果你不需要这个,你可以跳过函数调用convertFloat32ToInt16()

重要的

当您需要停止监听时,您必须断开处理器并结束流。运行下面的函数closeAll()

function closeAll() {
    const tracks = stream ? stream.getTracks() : null;
    const track = tracks ? tracks[0] : null;

    if (track) {
      track.stop();
    }

    if (processor) {
      if (input) {
        try {
          input.disconnect(processor);
        } catch (error) {
          console.warn('Attempt to disconnect input failed.');
        }
      }
      processor.disconnect(audioContext.destination);
    }

    if (audioContext) {
      audioContext.close().then(() => {
        input = null;
        processor = null;
        audioContext = null;
      });
    }
  }

Run Code Online (Sandbox Code Playgroud)