*Я создаю интерфейс React + Vite. В приложении у меня есть модуль преобразования голоса в текст, использующий Azure Speech SDK. Я захватываю аудио в браузере и отправляю фрагменты аудио PCM каждые 100 мс через WebSocket в службу Python.
В настоящее время я конвертирую фрагменты в клиенте (например, преобразование с понижением частоты/формата), и это преобразование вызывает зависание пользовательского интерфейса и не является оптимальным — клиент должен быть легким.
Я хотел бы знать: есть ли способ извлечь PCM аудиофрагменты непосредственно из браузера — без дорогостоящего преобразования на стороне клиента — чтобы клиент выполнял минимальную работу и отправлял «готовый к использованию» PCM на сервер?
*
// Recording Start Method
const handleStartRecording = async (
callBack: () => void,
socketInfo: WebSocket | null = socket.current
): Promise => {
try {
const mediaStream = await navigator.mediaDevices.getUserMedia({
audio: { channelCount: 1, sampleRate: 16000 }
})
const systemStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true
})
const audioContext = new AudioContext({ sampleRate: 16000 })
const destination = audioContext.createMediaStreamDestination()
if (systemStream?.getAudioTracks()?.length > 0) {
const micSource = audioContext.createMediaStreamSource(mediaStream)
const systemSource = audioContext.createMediaStreamSource(systemStream)
micSource.connect(destination)
systemSource.connect(destination)
} else {
console.warn("System audio was not shared. Only microphone will be captured.")
}
await audioContext.audioWorklet.addModule("/processor.js")
const pcmNode = new AudioWorkletNode(audioContext, "pcm-processor", {
channelCount: 1
})
const destinationStreamSource = audioContext.createMediaStreamSource(
destination.stream
)
destinationStreamSource.connect(pcmNode)
pcmNode.port.onmessage = (event) => {
const pcmChunk = event.data
if (
stateRef?.current === "RECORDING" &&
pcmChunk &&
pcmChunk.length > 0 &&
socketInfo?.readyState === WebSocket.OPEN
) {
socketInfo.send(pcmChunk.buffer)
}
}
setRecording(true)
setState("RECORDING")
setIsStarted(true)
setAudioContextState(audioContext)
setMediaStream(mediaStream)
setSystemStream(systemStream)
callBack()
} catch (err) {
console.error("Error capturing audio:", err)
}
}
// processor.js
class AudioProcessor extends AudioWorkletProcessor {
constructor() {
super()
this.buffer = []
this.bufferSize = sampleRate * 0.1
}
floatTo16BitPCM(float32Array) {
const int16Array = new Int16Array(float32Array.length)
for (let i = 0; i < float32Array.length; i++) {
let s = Math.max(-1, Math.min(1, float32Array))
int16Array = s < 0 ? s * 0x8000 : s * 0x7fff
}
return int16Array
}
process(inputs) {
const input = inputs?.[0]
if (!input || input.length === 0) return true
const inputChannel = input[0]
this.buffer.push(...inputChannel)
if (this.buffer.length >= this.bufferSize) {
const int16Chunk = this.floatTo16BitPCM(this.buffer)
this.port.postMessage(int16Chunk)
this.buffer = []
}
return true
}
}
registerProcessor("pcm-processor", AudioProcessor)
Подробнее здесь: https://stackoverflow.com/questions/798 ... sion-or-ui