web-dev-qa-db-ja.com

Node.jsとブラウザー間の音声チャット(オーディオストリーム、VoIP)

以前に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つのトラック(オーディオ)だけです。しかし、MediaStreamTrackstream のようには見えません。Node.jsから知っているように、単にパイプすることはできません。だから、多分それは一つに変換されなければならないでしょう。 microphone-stream と呼ばれるこの興味深いライブラリが見つかりました。しかし、それは単純なブラウザライブラリとしては利用できないようです。プロジェクト全体をbrowserifyでラップする必要があるようです。それは非常にやり過ぎのようです。シンプルにしたいのですが。

15
Forivin

すべての市長のブラウザーでサポートされているブラウザーでVoIPを実行するための標準が存在します: WebRTC 。それは恐ろしい複雑さの獣ですが、その複雑さを隠すすべての市長のブラウザーによって、箱から出してすぐにサポートされます。私はJavaScriptの開発者ではありませんが、JSの世界ではそれに対するゴールドサポートが存在していることを強く想定しています。 このブログ投稿

フル機能のオーバーキルソリューションが必要ない場合は、RTPストリーミングプロトコルとして使用します。これは、VoIPとOpusのエンコードの標準の一種です。どちらも十分に確立されたテクノロジです。 RTPは軽量で、Opusは高音質を維持しながら圧縮するのに効率的です。ブラウザとnode.jsのいずれかで十分にサポートされているはずです。環境。

注意:プレーンPCMを送信する場合は、すべてのパラメーターを正確に定義してください-フレーム長(8、16、32ビット)、符号付き/符号なし、整数/浮動小数点、および明示的にendianness

3
Michael Beer

生のPCMストリームを直接使用して、ブラウザーとnodejsアプリを接続しないでください。それはすぐにかなり無駄になる可能性があります。

一方、ノードで機能するものは、ブラウザで機能する場合と機能しない場合があります(リポジトリを確認して、何をしようとしているのかを確認し、そこで何かを確認できるかどうかを確認します)。

もう1つの解決策は、icecastのようなサーバーを使用することです。これにより、すべてのバックエンド/データが骨の折れるものになります。

次に、htmlタグだけでWebブラウザーを介して対話します。

これをチェック->()スタックオーバーフローで関連するスレッドへのリンクがありましたが、IT Lol()を失いました

よろしくお願いします。

2
Ian Franco Pozo

必要なライブラリの1つである socket.io と、最高のチュートリアルの1つである here です。あなたはそれを学ぶことができ、node.jsでチャットアプリを作成した後、ボイスチャットアプリを開始します

0
yasin

SFMediaStream は、ブラウザーからマイクオーディオデータをストリーミングするのに役立ち、socket.io。オーディオデータは、ブラウザーに応じてopusでエンコードされます。

また、ストリーマーにオーディオフィルター/エフェクトを与える機能があり、ライブラリを使用してビデオ/オーディオプレーヤーを構築することもできます。

多分あなたはこれをチェックした後に興味があります 基本的な例

0
StefansArya