Голосовой чат между Node.js и браузером (аудио потоки, VoIP) - PullRequest
0 голосов
/ 30 мая 2018

Раньше я делал голосовой чат между двумя серверами node.js (см .: tvoip ), который работает довольно хорошо, но теперь я хотел бы сделать это между сервером node.js и браузером.Как это можно сделать?
От node.js до node.js Я просто использовал необработанные потоки PCM через TCP-соединение.
Для браузера это, вероятно, будет не так просто, верно?Я имею в виду, что браузер на самом деле не предлагает TCP API.Он предлагает API WebSocket, но обрабатывает ли он потоки?Должен ли я конвертировать потоки и, если да, в какой формат и как?Какой протокол я должен использовать?Есть ли полезные библиотеки для достижения этой цели уже?Является ли 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>

Как видите, я нашел два решения.Я постараюсь основать голосовой чат узла <-> на втором браузере.

Для 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')

Найти правильный device для микрофона и динамика может быть немного сложнее, если вы не знакомы с ALSA под Linux. Здесь объясняется на случай, если вы не уверены.Я не уверен, как это работает на 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 () содержит интересный код.) и client.html .

Как видите, я пытаюсь отправитьдуплексный поток через соединение и направляет микрофонные входы в дуплексный поток и передает дуплексный поток на динамик на каждом конце (как я делал это в tvoip ).Это не работает банкомат, хотя.

Редактировать:

Я не уверен, правильно ли я это понял, но «поток», который я получаю от getUserMedia () - это MediaStream и этот медиапоток может иметь MediaStreamTrack s (аудио, видео или оба).Я в моем случае, очевидно, это был бы только один трек (аудио).Но MediaStreamTrack, похоже, не является потоком , как я знаю по Node.js, а это означает, что его нельзя просто передать по трубопроводу.Так что, возможно, это должно быть преобразовано в один.Я нашел эту интересную библиотеку под названием микрофон , которая утверждает, что может сделать это.Но он не доступен в виде простой библиотеки браузера.Кажется, требуется обернуть весь ваш проект с browserify.Который кажется очень излишним.Я бы хотел, чтобы все было просто.

Ответы [ 4 ]

0 голосов
/ 22 января 2019

SFMediaStream может помочь вам транслировать аудиоданные с микрофона из браузера, и вы можете транслировать их с помощью socket.io.Аудиоданные закодированы в opus в зависимости от браузера.

Он также имеет функцию для предоставления аудиофильтра / эффекта для стримера, и вы также можете использовать библиотеку для создания видео / аудио плеера.

Может быть, вам будет интересно после проверки этого базового примера

0 голосов
/ 06 июня 2018

Вы не должны напрямую использовать необработанные потоки PCM для соединения браузера и приложения nodejs.Это может стать довольно расточительным в кратчайшие сроки. С другой стороны,

, то, что работает в узле, может или не может работать в браузере (собираюсь проверить репо, чтобы увидеть, что вы пытаетесь сделать, и проверить, если яможете что-то там проверить) "

Другое решение - использовать сервер, такой как icecast, который будет выполнять все мелкие операции с бэкэндом / данными.

Затем вы взаимодействуете через веб-браузер.только с тегом html.

Проверьте это -> () У меня была ссылка на связанный поток в переполнении стека, но я потерял IT Lol ()

Но вы считаете это полезным, С уважением.

0 голосов
/ 11 июня 2018

Существует стандарт для VoIP с браузерами, который поддерживается всеми браузерами мэров: WebRTC .Несмотря на то, что это ужасный зверь сложности, он поддерживается сразу всеми браузерами мэров, которые скрывают его сложность.Я не являюсь разработчиком javascript, но я полагаю, что в мире JS существует поддержка золота, посмотрите, например, этот пост .

Если вы не хотите полнофункционального избыточного количестваРешение, я хотел бы вернуться к RTP в качестве потокового протокола, который является своего рода стандартом в VoIP и Opus для кодирования.Обе являются хорошо известными технологиями и образуют стандартную пару потоковой передачи VoIP, RTP легковесен, а Opus эффективен при сжатии, сохраняя при этом высокое качество звука.Они должны хорошо поддерживаться в средах Browser и node.js.

Осторожно: если вы решили отправить простой PCM, точно определите все параметры - длину кадра (8, 16, 32 бита),знаковое / беззнаковое, целое число / число с плавающей запятой и особенно порядковый номер !

0 голосов
/ 30 мая 2018

Одна из библиотек, в которой вы должны работать, это socket.io и один из лучших учебников - здесь .вы можете изучить его, и после того, как вы создали приложение для чата в node.js, запустите приложение для голосового чата

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...