La transmisión de transcripción multicanal es una característica de Amazon Transcribe Eso se puede usar en muchos casos con un navegador web. Crear esta fuente de transmisión tiene desafíos, pero con el API de audio web de JavaScriptpuede conectar y combinar diferentes fuentes de audio como videos, archivos de audio o hardware como micrófonos para obtener transcripciones.
En esta publicación, lo guiamos a través de cómo usar dos micrófonos como fuentes de audio, fusionarlos en un solo audio de doble canal, realizar la codificación requerida y transmitirlo a Amazon Transcribe. Se proporciona un código fuente de aplicación Vue.js que requiere dos micrófonos conectados a su navegador. Sin embargo, la versatilidad de este enfoque se extiende mucho más allá de este caso de uso: puede adaptarlo para acomodar una amplia gama de dispositivos y fuentes de audio.
Con este enfoque, puede obtener transcripciones para dos fuentes en una sola sesión de transcripción de Amazon, ofreciendo ahorros de costos y otros beneficios en comparación con el uso de una sesión separada para cada fuente.
Desafíos al usar dos micrófonos
Para nuestro caso de uso, utilizando una transmisión de un solo canal para dos micrófonos y habilitador Identificación de la etiqueta de altavoces de Amazon Transcribe Identificar los altavoces puede ser suficiente, pero hay algunas consideraciones:
- Las etiquetas de los altavoces se asignan aleatoriamente al inicio de la sesión, lo que significa que tendrá que mapear los resultados en su aplicación después de que el flujo haya comenzado
- Pueden ocurrir altavoces mal etiquetados con tonos de voz similares, que incluso para un humano es difícil de distinguir
- La superposición de la voz puede ocurrir cuando dos altavoces hablan al mismo tiempo con una fuente de audio
Al usar dos fuentes de audio con micrófonos, puede abordar estas preocupaciones asegurándose de que cada transcripción sea de una fuente de entrada fija. Al asignar un dispositivo a un altavoz, nuestra aplicación sabe de antemano qué transcripción usar. Sin embargo, aún puede encontrarse con la superposición de voz si dos micrófonos cercanos están recogiendo múltiples voces. Esto se puede mitigar utilizando micrófonos direccionales, gestión de volumen y Amazon Transcribe a nivel de palabra puntajes de confianza.
Descripción general de la solución
El siguiente diagrama ilustra el flujo de trabajo de la solución.
Usamos dos entradas de audio con la API de audio web. Con esta API, podemos fusionar las dos entradas, MIC A y MIC B, en una sola fuente de datos de audio, con el canal izquierdo que representa el micrófono A y el canal derecho que representa el micrófono B.
Luego, convertimos esta fuente de audio en audio PCM (modulación de código de pulso). PCM es un formato común para el procesamiento de audio, y es uno de los formatos requeridos por Amazon Transcribe para la entrada de audio. Finalmente, transmitimos el Audio PCM a Amazon Transcribe para la transcripción.
Requisitos previos
Debe tener los siguientes requisitos previos en su lugar:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DemoWebAudioAmazonTranscribe",
"Effect": "Allow",
"Action": "transcribe:StartStreamTranscriptionWebSocket",
"Resource": "*"
}
]
}
Iniciar la aplicación
Complete los siguientes pasos para iniciar la aplicación:
- Vaya al directorio root donde descargó el código.
- Cree un archivo .env para configurar sus claves de acceso AWS desde el
env.samplearchivo. - Instalar paquetes y ejecutar
bun install(Si estás usando nodo, ejecutenode install). - Iniciar el servidor web y ejecutar
bun dev(Si estás usando nodo, ejecutenode dev). - Abre tu navegador en
http://localhost:5173/.
Tutorial de código
En esta sección, examinamos las piezas de código importantes para la implementación:
- El primer paso es enumerar los micrófonos conectados utilizando la API del navegador
navigator.mediaDevices.enumerateDevices():
const devices = await navigator.mediaDevices.enumerateDevices()
return devices.filter((d) => d.kind === 'audioinput')
- A continuación, necesitas obtener el
MediaStreamObjeto para cada uno de los micrófonos conectados. Esto se puede hacer usando elnavigator.mediaDevices.getUserMedia()API, que permite acceder a los dispositivos de medios del usuario (como cámaras y micrófonos). Entonces puedes recuperar unMediaStreamobjeto que representa los datos de audio o video de esos dispositivos:
const streams = []
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId: device.deviceId,
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
},
})
if (stream) streams.push(stream)
- Para combinar el audio de los múltiples micrófonos, debe crear un Interfaz AudioContext para procesamiento de audio. Dentro de este
AudioContextpuedes usar ChannelMergerNode Para fusionar las transmisiones de audio de los diferentes micrófonos. Elconnect(destination, src_idx, ch_idx)Los argumentos del método son:- destino – El destino, en nuestro caso, MergerNode.
- src_idx -El índice de canal de origen, en nuestro caso, ambos (porque cada micrófono es una transmisión de audio de un solo canal).
- ch_idx – El índice de canal para el destino, en nuestro caso 0 y 1 respectivamente, para crear una salida estéreo.
// instance of audioContext
const audioContext = new AudioContext({
sampleRate: SAMPLE_RATE,
})
// this is used to process the microphone stream data
const audioWorkletNode = new AudioWorkletNode(audioContext, 'recording-processor', {...})
// microphone A
const audioSourceA = audioContext.createMediaStreamSource(mediaStreams[0]);
// microphone B
const audioSourceB = audioContext.createMediaStreamSource(mediaStreams[1]);
// audio node for two inputs
const mergerNode = audioContext.createChannelMerger(2);
// connect the audio sources to the mergerNode destination.
audioSourceA.connect(mergerNode, 0, 0);
audioSourceB.connect(mergerNode, 0, 1);
// connect our mergerNode to the AudioWorkletNode
merger.connect(audioWorkletNode);
- Los datos del micrófono se procesan en un Audioworklet Eso emite mensajes de datos cada número definido de cuadros de grabación. Estos mensajes contendrán los datos de audio codificados en formato PCM para enviar a Amazon Transcribe. Usando el P-EVENT Biblioteca, puede iterar asincrónicamente sobre los eventos del funcionario. Una descripción más profunda sobre este funcionario se proporciona en la siguiente sección de esta publicación.
import { pEventIterator } from 'p-event'
...
// Register the worklet
try {
await audioContext.audioWorklet.addModule('./worklets/recording-processor.js')
} catch (e) {
console.error('Failed to load audio worklet')
}
// An async iterator
const audioDataIterator = pEventIterator<'message', MessageEvent<AudioWorkletMessageDataType>>(
audioWorkletNode.port,
'message',
)
...
// AsyncIterableIterator: Every time the worklet emits an event with the message `SHARE_RECORDING_BUFFER`, this iterator will return the AudioEvent object that we need.
const getAudioStream = async function* (
audioDataIterator: AsyncIterableIterator<MessageEvent<AudioWorkletMessageDataType>>,
) {
for await (const chunk of audioDataIterator) {
if (chunk.data.message === 'SHARE_RECORDING_BUFFER') {
const { audioData } = chunk.data
yield {
AudioEvent: {
AudioChunk: audioData,
},
}
}
}
}
- Para comenzar a transmitir los datos a Amazon Transcribe, puede usar el iterador fabricado y habilitado
NumberOfChannels: 2yEnableChannelIdentification: truepara habilitar la transcripción de doble canal. Para obtener más información, consulte el AWS SDK StartStreamTranscriptionCommand documentación.
import {
LanguageCode,
MediaEncoding,
StartStreamTranscriptionCommand,
} from '@aws-sdk/client-transcribe-streaming'
const command = new StartStreamTranscriptionCommand({
LanguageCode: LanguageCode.EN_US,
MediaEncoding: MediaEncoding.PCM,
MediaSampleRateHertz: SAMPLE_RATE,
NumberOfChannels: 2,
EnableChannelIdentification: true,
ShowSpeakerLabel: true,
AudioStream: getAudioStream(audioIterator),
})
- Después de enviar la solicitud, se crea una conexión WebSocket para intercambiar datos de transmisión de audio y los resultados de transcripción de Amazon:
const data = await client.send(command)
for await (const event of data.TranscriptResultStream) {
for (const result of event.TranscriptEvent.Transcript.Results || []) {
callback({ ...result })
}
}
El result El objeto incluirá un ChannelId propiedad que puede usar para identificar su fuente de micrófono, como ch_0 y ch_1respectivamente.
Dive Deep: Audio Worklet
Los trabajadores de audio pueden ejecutarse en un hilo separado para proporcionar un procesamiento de audio de muy baja latencia. El código fuente de implementación y demostración se puede encontrar en el public/worklets/recording-processor.js archivo.
Para nuestro caso, usamos el funcionario para realizar dos tareas principales:
- Procesar el
mergerNodeaudio de una manera iterable. Este nodo incluye nuestros dos canales de audio y es la entrada a nuestro trabajo. - Codificar los bytes de datos del
mergerNodeNodo en PCM Formato de audio pequeño de 16 bits Little Endian. Hacemos esto para cada iteración o cuando se requiere para emitir una carga útil de mensajes a nuestra aplicación.
La estructura de código general para implementar esto es la siguiente:
class RecordingProcessor extends AudioWorkletProcessor {
constructor(options) {
super()
}
process(inputs, outputs) {...}
}
registerProcessor('recording-processor', RecordingProcessor)
Puede pasar opciones personalizadas a esta instancia de funcionario utilizando el processorOptions atributo. En nuestra demostración, establecemos un maxFrameCount: (SAMPLE_RATE * 4) / 10 Como una guía de tasa de bits para determinar cuándo emitir una nueva carga útil de mensajes. Un mensaje es por ejemplo:
this.port.postMessage({
message: 'SHARE_RECORDING_BUFFER',
buffer: this._recordingBuffer,
recordingLength: this.recordedFrames,
audioData: new Uint8Array(pcmEncodeArray(this._recordingBuffer)), // PCM encoded audio format
})
Codificación de PCM para dos canales
Una de las secciones más importantes es cómo codificar a PCM para dos canales. Siguiendo la documentación de AWS en Amazon Transcribe Referencia de APIel audiochunk se define por: Duration (s) * Sample Rate (Hz) * Number of Channels * 2. Para dos canales, 1 segundo a 16000Hz es: 1 * 16000 * 2 * 2 = 64000 bytes. Nuestra función de codificación debería verse así:
// Notice that input is an array, where each element is a channel with Float32 values between -1.0 and 1.0 from the AudioWorkletProcessor.
const pcmEncodeArray = (input: Float32Array[]) => {
const numChannels = input.length
const numSamples = input[0].length
const bufferLength = numChannels * numSamples * 2 // 2 bytes per sample per channel
const buffer = new ArrayBuffer(bufferLength)
const view = new DataView(buffer)
let index = 0
for (let i = 0; i < numSamples; i++) {
// Encode for each channel
for (let channel = 0; channel < numChannels; channel++) {
const s = Math.max(-1, Math.min(1, input[channel][i]))
// Convert the 32 bit float to 16 bit PCM audio waveform samples.
// Max value: 32767 (0x7FFF), Min value: -32768 (-0x8000)
view.setInt16(index, s < 0 ? s * 0x8000 : s * 0x7fff, true)
index += 2
}
}
return buffer
}
Para obtener más información sobre cómo se manejan los bloques de datos de audio, consulte AudioWorkletProcessor: Process () método. Para obtener más información sobre la codificación del formato PCM, consulte Interfaz de programación multimedia y especificaciones de datos 1.0.
Conclusión
En esta publicación, exploramos los detalles de implementación de una aplicación web que utiliza la API de audio web del navegador y la transcripción de Amazon Transcribe para habilitar la transcripción de doble canal en tiempo real. Utilizando la combinación de AudioContext, ChannelMergerNodey AudioWorkletpudimos procesar y codificar sin problemas los datos de audio de dos micrófonos antes de enviarlos a Amazon Transcribe para la transcripción. El uso del AudioWorklet En particular, nos permitió lograr un procesamiento de audio de baja latencia, proporcionando una experiencia de usuario suave y receptiva.
Puede construir sobre esta demostración para crear aplicaciones de transcripción en tiempo real más avanzadas que se adapten a una amplia gama de casos de uso, desde grabaciones de reuniones hasta interfaces controladas por voz.
Pruebe la solución por sí mismo y deje sus comentarios en los comentarios.
Sobre el autor
Jorge Lanzarotti es un prototipo de SR en Amazon Web Services (AWS) basado en Tokio, Japón. Ayuda a los clientes en el sector público creando soluciones innovadoras para problemas desafiantes.