使用套接字 IO 和 Node JS 通过套接字流式传输麦克风

Posted

技术标签:

【中文标题】使用套接字 IO 和 Node JS 通过套接字流式传输麦克风【英文标题】:Streaming microphone through sockets using socket IO and Node JS 【发布时间】:2014-11-03 07:38:32 【问题描述】:

我正在制作一个应用程序,我希望用户使用他们的麦克风(在他们的手机上)并能够在游戏大厅中相互交谈。然而,事实证明这不仅仅是困难。

我正在使用 Node JS 套接字 io 和套接字 io 流

在我的客户端上,我使用音频 api 来获取我的麦克风输入(我并不太担心这一切,因为我将把它变成一个原生 ios 应用程序)

    navigator.getUserMedia = ( navigator.getUserMedia ||
                     navigator.webkitGetUserMedia ||
                     navigator.mozGetUserMedia ||
                     navigator.msGetUserMedia);

    if (navigator.getUserMedia) 
          navigator.getUserMedia (
            // constraints
          
            video: false,
            audio: true
          ,


    function(localMediaStream) 
        var video = document.querySelector('audio');
        video.src = window.URL.createObjectURL(localMediaStream);
       lcm = localMediaStream;
       var audioContext = window.AudioContext;
       var context = new audioContext();
       var audioInput = context.createMediaStreamSource(localMediaStream);
       var bufferSize = 2048;
      // create a javascript node
      var recorder = context.createScriptProcessor(bufferSize, 1, 1);
      // specify the processing function
      recorder.onaudioprocess = recorderProcess;
      // connect stream to our recorder
      audioInput.connect(recorder);
      // connect our recorder to the previous destination
      recorder.connect(context.destination);
      ,

  // errorCallback
  function(err) 
     console.log("The following error occured: " + err);
     $("video").remove();
     alert("@#");
          
        );
             else 
                 console.log("getUserMedia not supported");
            

        function recorderProcess(e) 
            var left = e.inputBuffer.getChannelData(0);
            window.stream.write(convertFloat32ToInt16(left));
           //var f = $("#aud").attr("src");
           var src = window.URL.createObjectURL(lcm);
            ss(socket).emit('file', src, size: src.size);
           ss.createBlobReadStream(src).pipe(window.stream);
          //ss.createReadStream(f).pipe(widnow.stream);

            
         function convertFloat32ToInt16(buffer)
       
            l = buffer.length;
            buf = new Int16Array(l);
            while (l--) 
               buf[l] = Math.min(1, buffer[l])*0x7FFF;
                    
           return buf.buffer;
         



             );

         ss(socket).on('back', function(stream, data) 

                //console.log(stream);

                var video = document.querySelector('audio');
              video.src = window.URL.createObjectURL(stream);
              console.log("getting mic data");
            );

我可以成功地在麦克风上听到我的自言自语。我正在使用流套接字创建一个 blob 以上传到我的服务器...

        index.ss(socket).on('file', function(stream, data) 
                console.log("getting stream");
               var filename = index.path.basename(data.name);
             //var myfs = index.fs.createWriteStream(filename);

            var fileWriter = new index.wav.FileWriter('demo.wav', 
                channels: 1,
                sampleRate: 48000,
                bitDepth: 16
             );
          var streams = index.ss.createStream();
          streams.pipe(fileWriter);

        index.ss(socket).emit('back', fileWriter, size: fileWriter.size);


        );

我无法将流写入文件甚至临时缓冲区,然后流回客户端,以便我可以实时播放或“流式传输”音频。一段时间后,服务器崩溃并说管道不可写。

有没有其他人遇到过这种情况?

【问题讨论】:

可以在本地播放创建的blob吗? 通过 usig : var src = window.URL.createObjectURL(lcm);我可以播放我的麦克风。但是我不知道套接字 io 何时创建 blob 是否是正确的 blob 文件,因为它将它发送到服务器,并且我找不到将其保留在本地客户端 @dandavis 的方法 2 件事:1,您可以将 blob 转换为 dataURL 并发送它(性能有所降低,但工作总比没有快 100%)。 2、可以使用Chrome devtools network tab来监控socket流量,在network tab的url list的item details页面的frames tab上。 其传输正确。我肯定知道。我的问题是我想知道解决此解决方案的最佳方法是如何跨多个平台向客户端提供音频数据。如果我有很多客户端,我认为数据 URL 的可扩展性不高。这也将与实际游戏同时运行,所以我必须高效 dataURL 只会增加约 33% 的开销。您应该能够使用 socket.io 发出一个 blob。混合是可能的:在节点中捕获 dataURL,转换为 blob,然后广播 blob。如果 dataURL 转换或只是捆绑通常很慢,您可以使用工作线程来保持游戏循环流畅。尝试获取节点广播本地的真实文件作为要调试的 blob。 【参考方案1】:

通过使用SFMediaStream library,您可以使用socket.io 和Nodejs 服务器从浏览器实时流式传输您的麦克风。但是这个库在发布到生产环境之前还需要一些改进。

对于演示者

var mySocket = io("/", transports:['websocket']);

// Set latency to 100ms (Equal with streamer)
var presenterMedia = new ScarletsMediaPresenter(
    audio:
        channelCount:1,
        echoCancellation: false
    
, 100);

// Every new client streamer must receive this header buffer data
presenterMedia.onRecordingReady = function(packet)
    mySocket.emit('bufferHeader', packet);


// Send buffer to the server
presenterMedia.onBufferProcess = function(streamData)
    mySocket.emit('stream', streamData);


presenterMedia.startRecording();

对于主播

var mySocket = io("/", transports:['websocket']);

// Set latency to 100ms (Equal with presenter)
var audioStreamer = new ScarletsAudioBufferStreamer(100);
audioStreamer.playStream();

// Buffer header must be received first
mySocket.on('bufferHeader', function(packet)
    audioStreamer.setBufferHeader(packet);
);

// Receive buffer and play it
mySocket.on('stream', function(packet)
    // audioStreamer.realtimeBufferPlay(packet);
    audioStreamer.receiveBuffer(packet);
);

// Request buffer header
mySocket.emit('requestBufferHeader', '');

或者您可以使用this example从本地主机测试它

【讨论】:

那也有手机版吗?像 react-native 一样? 有趣.. 由于我的 PC 资源有限,我还没有尝试过 react-native,但它应该支持带有 Cordova 的 WebView。

以上是关于使用套接字 IO 和 Node JS 通过套接字流式传输麦克风的主要内容,如果未能解决你的问题,请参考以下文章

Node.js + Socket.io 在套接字中存储数据

使用套接字将数据从 node.js 发送到 Java

Socket.io node.js,如何避免记录连接时间或考虑页面刷新/多个套接字?

c# SocketIoClientDotNet, node js socket.IO

node.js + socket.io + redis 架构 - 水平服务器缩放套接字连接?

在重新连接、socket.io、node.js 时重用套接字 id