在这个问题上碰壁:使用大多数相同的功能来进行 AWS Transcribe 流式传输。我已经包括了我认为可能导致问题的相关部分。
首先,我能够解组消息并且它看起来正确(标题都在那里并格式化) - 这让我相信我正确地创建了数据结构。这让我觉得我一定是对有效载荷进行了编码或编码不当。
与某些 aws 转录文档资源不同的注意事项。在 websocket 文档中,它显示了三个标头(八位字节流),但我将其删除以更符合 github 上的静态转录 websocket 示例(请参阅 getAudioEventMessage)。我尝试使用/不使用此标头格式化消息。
以下是我认为的相关代码部分。如果有人希望我扩展,我会附加额外的代码。
首先,我使用音频上下文拉入流,数据正在填充并且看起来正确。
const handleSuccess = function (stream) {
const context = new AudioContext();
const source = context.createMediaStreamSource(stream);
const processor = context.createScriptProcessor(1024, 1, 1);
source.connect(processor);
processor.connect(context.destination);
processor.onaudioprocess = function (e) {
if (isRecording) {
ProcessStream(e.inputBuffer);
}
};
};
在我的视图上点击记录按钮后,会触发一个事件,该事件会为我的 websocket 获取正确签名/格式化的 url,这运行良好,并且连接无缝发生。套接字被打开,并在处理音频数据时将其发送到下面的 ProcessStream。socket.send(message) 返回无法解码音频数据的响应。我经历过一些错误,例如无效的 Web 套接字框架等等。我的问题可能在于我如何处理audioChunk。
function ProcessStream(audioChunk) {
var eventStreamMarshaller = new EventStreamMarshaller();
var inputSampleRate = audioChunk.sampleRate;
var transcribeSampleRate = 16000;
var raw = audioChunk.getChannelData(0);
if (raw == null) return;
var downsampledBuffer = downsampleBuffer(raw, inputSampleRate, transcribeSampleRate);
var pcmEncodedBuffer = pcmEncode(downsampledBuffer);
var audioEventMessage = getAudioEventMessage(pcmEncodedBuffer);
var message = eventStreamMarshaller.marshall(audioEventMessage);
// console.log(eventStreamMarshaller.unmarshall(message));
socket.send(message);
}
这会在编组之前将音频事件消息格式化为 AWS Transcribe EventStream 规范。
function getAudioEventMessage(buffer) {
return {
headers: {
':event-type': {
type: 'string',
value: 'AudioEvent',
},
':message-type': {
type: 'string',
value: 'event',
},
},
body: buffer
};
}
我现在没有使用 NodeJS,我不完全理解的一件事是在格式化事件消息之前完成的 Buffer.From(pcmEncodedBuffer) 调用。我已经尝试过 base64 编码并将其包装在 arrayBuffer 中,以及 nodejs 文档中对 Buffer.From(ArrayBuffer) 的描述中的其他一些内容。
错误:无法解码您提供的音频流。(错误的请求异常)。
附加功能:
function downsampleBuffer(buffer, inputSampleRate = 44100, outputSampleRate = 16000) {
if (outputSampleRate === inputSampleRate) {
return buffer;
}
var sampleRateRatio = inputSampleRate / outputSampleRate;
var newLength = Math.round(buffer.length / sampleRateRatio);
var result = new Float32Array(newLength);
var offsetResult = 0;
var offsetBuffer = 0;
while (offsetResult < result.length) {
var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
var accum = 0,
count = 0;
for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
accum += buffer[i];
count++;
}
result[offsetResult] = accum / count;
offsetResult++;
offsetBuffer = nextOffsetBuffer;
}
return result;
}
function pcmEncode(input) {
var offset = 0;
var buffer = new ArrayBuffer(input.length * 2);
var view = new DataView(buffer);
for (var i = 0; i < input.length; i++, offset += 2) {
var s = Math.max(-1, Math.min(1, input[i]));
view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
return buffer;
}