Я так близок к тому, чтобы звуковой чат работал через Websockets. Идея этого приложения, которое я создаю, состоит в том, чтобы групповой голосовой чат работал в браузере.
Я использую сервер socket.io для передачи этой информации.
Звук передается хорошо. Используется этот код:
let hasHeader = false
export function emitAudioStream(mic, sock, room) {
console.log('beginning record')
const recorder = new MediaRecorder(mic)
recorder.ondataavailable = (evt) => {
// fetch the header
if (!hasHeader) {
console.log('header:', evt.data)
sock.emit('header:audio', evt.data)
hasHeader = true
}
// console.log(evt.data.size)
sock.emit('stream:audio', ({room, streamData: evt.data}))
}
recorder.start()
console.log(`Recording begin. (State: "${recorder.state}")`)
setInterval(() => {
recorder.requestData()
}, 1e3/60)
}
Есть комнаты «участников» - подключенных физических лиц. Сервер обрабатывает запросы следующим образом:
sock.on('header:audio', (packet) => {
console.log(`setting audio header for ${sock.id}`)
sock.__audioHeader = packet
})
sock.on('stream:audio', ({room, streamData}) => {
const participants = rooms[room]
if (!participants) {
console.log(`not found ${room} room`)
return
}
// create a getParticipants to handle not found
// add flag to include current socket
participants.forEach(participant => {
// if (participant.id === sock.id) return
participant.emit('stream:audio:packet', {header: sock.__audioHeader, streamData})
})
})
Снова на клиенте, где я пытаюсь играть (где все это не удается), это выглядит так. Скорее всего, я неправильно истолковал документы Web Audio. Может ли кто-нибудь указать мне правильное направление / объяснить, почему это неправильный подход?
sck.on('stream:audio:packet', ({header, streamData}) => {
playSound(streamData)
})
function playSound(buffer) {
const context = new AudioContext()
var source = context.createBufferSource()
source.buffer = buffer
source.connect(context.destination)
source.start(0)
}
Другая попытка декодирования, которую я использовал:
sck.on('stream:audio:packet',async ({header, streamData}) => {
if (streamData === 'data:') return
const b64ToBuffer = (data) => fetch(data).then(r => r.blob())
const buff = await b64ToBuffer(streamData)
playSound(await buff.arrayBuffer())
})
let context = new AudioContext()
async function playSound(buffer) {
try {
const buff = await context.decodeAudioData(buffer)
let source = context.createBufferSource()
source.connect(context.destination)
console.log(buff)
source.buffer = buff
source.start(0)
} catch (err) {
console.warn('error decoding data:', err)
}
}