我之前在两个node.js服务器之间进行了语音聊天(请参阅:tvoip),这很有效,但现在我想在node.js服务器和浏览器之间进行。怎么可以这样做?
从node.js到node.js我只是通过TCP连接使用原始PCM流
对于浏览器来说,这可能不会那么容易,对吧?我的意思是浏览器并不真正提供TCP API。它确实提供了WebSocket API,但它是否处理流?我是否必须将流转换成什么格式以及如何转换?我应该使用什么协议?是否有任何有用的库来实现这一目标? socket.io-stream是一个可行的库来发送这些类型的流吗?
根据我的理解,音频流在浏览器上采用PCM格式。所以它应该与我在Node.js中获得的流相匹配。这个假设是否正确?
我设法将浏览器麦克风输入传输到浏览器扬声器输出,如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<!-- alternative method that also works
<audio></audio>
<script>
navigator.mediaDevices.getUserMedia({ audio: true }).then(function(stream) {
const audio = document.querySelector('audio')
audio.srcObject = stream
audio.onloadedmetadata = function(e) {
audio.play()
}
}).catch(console.error)
</script>
-->
<script>
navigator.mediaDevices.getUserMedia({audio: true}).then(stream => {
const aCtx = new AudioContext()
const analyser = aCtx.createAnalyser()
const microphone = aCtx.createMediaStreamSource(stream)
microphone.connect(analyser)
analyser.connect(aCtx.destination)
}).catch(err => {
console.error("Error getting audio stream from getUserMedia")
})
</script>
</body>
</html>
如你所见,我找到了两个解决方案。我将尝试在第二个节点上建立节点&lt; - &gt;浏览器语音聊天。
对于Node.js,我想出了这个代码来将node.js mic输入传递给node.js扬声器输出:
const mic = require('mic')
const Speaker = require('speaker')
const micInstance = mic({ // arecord -D hw:0,0 -f S16_LE -r 44100 -c 2
device: 'hw:2,0', // -D hw:0,0
encoding: 'signed-integer', // -f S
bitwidth: '16', // 16
endian: 'little', // _LE
rate: '44100', // -r 44100
channels: '1', // -c 2
debug: true
})
const micInputStream = micInstance.getAudioStream()
const speakerInstance = new Speaker({ // | aplay -D plughw:CARD=0,DEV=0
channels: 1,
bitDepth: 16,
sampleRate: 44100,
signed: true,
device: 'plughw:2,0' //'plughw:NVidia,7'
})
speakerInstance.on('open', ()=>{
console.log("Speaker received stuff")
})
// Pipe the readable microphone stream to the writable speaker stream:
micInputStream.pipe(speakerInstance)
micInputStream.on('data', data => {
//console.log("Recieved Input Stream: " + data.length)
})
micInputStream.on('error', err => {
cosole.log("Error in Input Stream: " + err)
})
micInstance.start()
console.log('Started')
如果您不熟悉Linux下的ALSA,那么找到适合麦克风和扬声器的device
可能会有点棘手。 It is explained here万一你不确定。我不确定它如何在Windows和Mac OS上使用SoX。
然后我想出了一个小的测试应用程序,用socket.io-stream(一个允许通过套接字发送流的socket.io库)连接这两个想法。显然,这是我坚持的地方。
基本上,我在node.js端试试这个:
const mic = require('mic')
const Speaker = require('speaker')
const SocketIO = require('socket.io')
const ss = require('socket.io-stream')
...
io.on('connection', socket => {
let micInstance = mic(micConfig)
let micInputStream = micInstance.getAudioStream()
let speakerInstance = new Speaker(speakerConfig)
...
ss(socket).on('client-connect', (stream, data) => { // stream: duplex stream
stream.pipe(speakerInstance) //speakerInstance: writable stream
micInputStream.pipe(stream) //micInputStream: readable stream
micInstance.start()
})
})
这在浏览器端:
const socket = io()
navigator.mediaDevices.getUserMedia({audio:true}).then(clientMicStream => { // Get microphone input
// Create a duplex stream using the socket.io-stream library's ss.createStream() method and emit it it to the server
const stream = ss.createStream() //stream: duplex stream
ss(socket).emit('client-connect', stream)
// Send microphone input to the server by piping it into the stream
clientMicStream.pipe(stream) //clientMicStream: readable stream
// Play audio received from the server through the stream
const aCtx = new AudioContext()
const analyser = aCtx.createAnalyser()
const microphone = aCtx.createMediaStreamSource(stream)
microphone.connect(analyser)
analyser.connect(aCtx.destination)
}).catch(e => {
console.error('Error capturing audio.')
alert('Error capturing audio.')
})
整个代码可在以下位置查看:https://github.com/T-vK/node-browser-audio-stream-test
(README.md包含有关如何设置它的说明,如果你想测试它。)相关代码在server.js(setupStream()函数包含有趣的代码。)和{{3 }}
正如您所看到的,我正在尝试通过连接发送双工流,并将麦克风输入传输到双工流中,并将双工流传输到每端的扬声器(就像我在client.html中所做的那样)。但它不起作用。
编辑:
我不确定我是否正确,但我从tvoip获得的“流”是getUserMedia(),此媒体流可以有MediaStream s(音频,视频或两者兼而有之)我是我的情况,它显然只是一个轨道(音频)。但是MediaStreamTrack
似乎不是MediaStreamTrack,因为我从Node.js中知道它,这意味着它不能只是用管道传输。所以也许它必须转换成一个。我找到了这个名为stream的有趣库,声称能够做到这一点。但它似乎不是一个简单的浏览器库。似乎需要使用browserify包装整个项目。这似乎非常矫枉过正。我想保持简单。
答案 0 :(得分:3)
所有市长浏览器都支持使用浏览器进行VoIP的标准:WebRTC。虽然是一个复杂的可怕野兽,但所有市长浏览器都支持它,它隐藏了它的复杂性。我不是javascript开发人员,但我高度认为在JS世界中存在黄金支持,例如, this blogpost
如果您不想要全功能的矫枉过正解决方案,我会将RTP作为流媒体协议退回,这是VoIP和Opus编码的标准。 两者都是成熟的技术,形成一种默认的VoIP流,RTP是轻量级的,而Opus在压缩时效率高,同时保证了高音质。它们应该在Browser和node.js环境中得到很好的支持。
注意:如果您决定发送普通PCM,请精确定义所有参数 - 帧长度(8,16,32位),a 有符号/无符号,整数/浮点数,尤其是 endianness !
答案 1 :(得分:2)
您不应该直接使用原始PCM流将浏览器和nodejs应用程序连接在一起。它很快就会变得非常浪费。
另一方面,什么在节点中工作,可能会或可能不会在浏览器中工作(去检查你的回购看看你想要做什么,并检查我是否可以在那里检查一些东西)&#34;
另一种解决方案是使用像icecast一样的服务器,这将使所有后端/数据变得非常粗糙。
然后,您只需使用html标记通过网络浏览器进行互动。
检查一下 - &gt; () 我有一个链接溢出相关线程的链接,但我丢失了IT Lol()
你发现这很有用, 问候。
答案 2 :(得分:0)
答案 3 :(得分:0)
SFMediaStream可以帮助您从浏览器流式传输麦克风音频数据,并且可以使用socket.io
进行广播。视浏览器而定,音频数据以opus
编码。
它还具有为流媒体提供音频过滤器/效果的功能,您还可以使用该库来构建视频/音频播放器。
也许选中此basic example
后,您会感兴趣