首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Node.js和浏览器之间的语音聊天(音频流、VoIP)

Node.js和浏览器之间的语音聊天(音频流、VoIP)
EN

Stack Overflow用户
提问于 2018-05-30 22:45:15
回答 3查看 8.5K关注 0票数 15

我以前在两个node.js服务器之间做过语音聊天(参见:tvoip),它工作得很好,但现在我想在node.js服务器和浏览器之间做这件事。如何做到这一点呢?

从node.js到node.js,我只是在TCP连接上使用原始的PCM流。

对于浏览器来说,这可能不会那么容易,对吧?我的意思是,浏览器并没有真正提供TCP API。它确实提供了一个WebSocket应用程序接口,但是它能处理流吗?我是否必须将流转换为什么格式以及如何转换?我应该使用什么协议?已经有什么有用的库来完成这个任务了吗?socket.io-stream是一个可行的库来发送这些类型的流吗?

据我所知,浏览器上的音频流是PCM格式的。因此,它应该与我在Node.js中获得的流兼容。这个假设是正确的吗?

我已经设法将浏览器麦克风输入输送到浏览器扬声器输出,如下所示:

代码语言:javascript
复制
<!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>

如你所见,我找到了两个解决方案。我将尝试将节点<->浏览器语音聊天基于第二个节点。

对于Node.js,我想出了以下代码来将node.js麦克风输入输送到node.js扬声器输出:

代码语言:javascript
复制
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下的device,那么为麦克风和扬声器找到合适的ALSA可能有点棘手。It is explained here,以防您不确定。我不确定它在装有SoX的视窗和Mac上是如何工作的。

然后,我想出了一个使用socket.io-stream (一个允许通过套接字发送流的socket.io库)的小测试应用程序来连接这两个想法。显然,这就是我被困在这里的地方。

基本上,我在node.js端尝试这样做:

代码语言:javascript
复制
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()
    })
})

在浏览器端是这样的:

代码语言:javascript
复制
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()函数包含有趣的代码)。和client.html

正如您所看到的,我正在尝试通过连接发送双工数据流,并将麦克风输入通过管道传输到双工数据流,然后将双工数据流通过管道传输到两端的扬声器(就像我在tvoip中所做的那样)。但它不能在自动取款机上工作。

编辑:

我不确定我是否正确,但是我从getUserMedia()得到的“流”是一个MediaStream,这个媒体流可以有MediaStreamTracks (音频、视频或两者都有)。以我为例,它显然只有一首曲目(音频)。但我从Node.js中了解到,MediaStreamTrack似乎不是stream,这意味着它不能只是通过管道传输。因此,可能必须将其转换为一个。我发现了一个名为microphone-stream的有趣的库,它声称能够做到这一点。但它似乎并不是一个简单的浏览器库。这似乎需要用browserify来包装整个项目。这看起来太过分了。我想让它保持简单。

EN

回答 3

Stack Overflow用户

发布于 2018-06-07 00:10:17

不应直接使用原始PCM流将浏览器和nodejs应用连接在一起。它很快就会变得非常浪费。

另一方面,在node中工作的东西在浏览器中可能工作,也可能不工作(我将检查你的存储库,看看你正在尝试做什么,并检查我是否可以在那里检查一些东西)。

另一种解决方案是使用类似服务器的icecast -,这将使所有后端/数据变得粗糙。

然后,您只需使用一个html标签就可以通过web浏览器进行交互。

检查这个-> ()我有一个指向堆栈溢出中相关线程的链接,但我丢失了Lol()

Hpe你会发现这是有用的,致敬。

票数 2
EN

Stack Overflow用户

发布于 2019-01-22 21:58:55

SFMediaStream可以帮助您从浏览器流式传输麦克风音频数据,并且您可以使用socket.io进行广播。根据浏览器的不同,音频数据以opus格式进行编码。

它还具有为streamer提供音频过滤器/效果的功能,您还可以使用该库来构建视频/音频播放器。

也许您在查看此basic example后会感兴趣

票数 1
EN

Stack Overflow用户

发布于 2018-05-30 23:00:52

其中一个库是你必须工作的,它的socket.io和最好的教程之一是它的here。您可以学习它,在node.js中创建聊天应用程序后,然后启动语音聊天应用程序

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50607578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档