以前に2つのnode.jsサーバー間で音声チャットを行ったことがあります(参照: tvoip )。これは非常にうまく機能しますが、今はnode.jsサーバーとブラウザー間でやりたいと思います。これはどのように行うことができますか?
node.jsからnode.jsへTCP接続で生のPCMストリームを使用しました。
ブラウザの場合、これはおそらくそれほど簡単ではありませんよね?つまり、ブラウザはTCP APIを実際には提供していません。WebSocketAPIを提供していますが、ストリームを処理しますか?ストリームを変換する必要がありますか。 ?どのプロトコルを使用する必要がありますか?これを達成するのに役立つライブラリはありますか? 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>
ご覧のとおり、2つの解決策を見つけました。ノード<->ブラウザのボイスチャットを2番目のものに基づいて試してみます。
Node.jsの場合、node.jsマイク入力を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
を見つけるのは少し難しいかもしれません。 ここで説明します わからない場合。 WindowsとMac OSでSoXがどのように機能するかはわかりません。
次に、socket.io-stream(ソケットを介してストリームを送信できるようにするsocket.ioライブラリ)を使用して2つのアイデアを接続する小さなテストアプリケーションを思い付きました。そして、明らかに、これは私が行き詰まっているところです。
基本的に、私はこれを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()関数には興味深いコードが含まれています。)および client.html 。
ご覧のように、接続を介してデュプレックスストリームを送信し、マイク入力をデュプレックスストリームにパイプし、デュプレックスストリームを両端のスピーカーにパイプします( tvoip で行ったように)。 )。ただし、ATMは機能しません。
編集:
これが正しいかどうかはわかりませんが、 getUserMedia() から取得する「ストリーム」は MediaStream であり、このメディアストリームは MediaStreamTrack s(オーディオ、ビデオ、またはその両方)。私の場合は、明らかに1つのトラック(オーディオ)だけです。しかし、MediaStreamTrack
は stream のようには見えません。Node.jsから知っているように、単にパイプすることはできません。だから、多分それは一つに変換されなければならないでしょう。 microphone-stream と呼ばれるこの興味深いライブラリが見つかりました。しかし、それは単純なブラウザライブラリとしては利用できないようです。プロジェクト全体をbrowserifyでラップする必要があるようです。それは非常にやり過ぎのようです。シンプルにしたいのですが。
すべての市長のブラウザーでサポートされているブラウザーでVoIPを実行するための標準が存在します: WebRTC 。それは恐ろしい複雑さの獣ですが、その複雑さを隠すすべての市長のブラウザーによって、箱から出してすぐにサポートされます。私はJavaScriptの開発者ではありませんが、JSの世界ではそれに対するゴールドサポートが存在していることを強く想定しています。 このブログ投稿 。
フル機能のオーバーキルソリューションが必要ない場合は、RTPストリーミングプロトコルとして使用します。これは、VoIPとOpusのエンコードの標準の一種です。どちらも十分に確立されたテクノロジです。 RTPは軽量で、Opusは高音質を維持しながら圧縮するのに効率的です。ブラウザとnode.jsのいずれかで十分にサポートされているはずです。環境。
注意:プレーンPCMを送信する場合は、すべてのパラメーターを正確に定義してください-フレーム長(8、16、32ビット)、符号付き/符号なし、整数/浮動小数点、および明示的にendianness!
生のPCMストリームを直接使用して、ブラウザーとnodejsアプリを接続しないでください。それはすぐにかなり無駄になる可能性があります。
一方、ノードで機能するものは、ブラウザで機能する場合と機能しない場合があります(リポジトリを確認して、何をしようとしているのかを確認し、そこで何かを確認できるかどうかを確認します)。
もう1つの解決策は、icecastのようなサーバーを使用することです。これにより、すべてのバックエンド/データが骨の折れるものになります。
次に、htmlタグだけでWebブラウザーを介して対話します。
これをチェック->()スタックオーバーフローで関連するスレッドへのリンクがありましたが、IT Lol()を失いました
よろしくお願いします。
SFMediaStream は、ブラウザーからマイクオーディオデータをストリーミングするのに役立ち、socket.io
。オーディオデータは、ブラウザーに応じてopus
でエンコードされます。
また、ストリーマーにオーディオフィルター/エフェクトを与える機能があり、ライブラリを使用してビデオ/オーディオプレーヤーを構築することもできます。
多分あなたはこれをチェックした後に興味があります 基本的な例