AWS Transcribe Streaming BadRequestException:"Could not decode the audio stream..."
AWS Transcribe Streaming BadRequestException: "Could not decode the audio stream..."
我正在使用 websockets 在 Dart/Flutter 中构建一个 Transcribe Streaming 应用程序。当我流式传输测试音频(从单声道、16kHz、16 位签名的小端 WAV 文件中提取)时,我得到...
BadRequestException: Could not decode the audio stream that you provided. Check that the audio stream is valid and try your request again.
作为测试,我正在使用文件流式传输音频。我每秒发送 32k 数据字节(大致模拟实时麦克风流)。如果我流式传输所有 0x00 或所有 0xFF 或随机字节,我什至会收到错误消息。如果我将块大小划分为 16k,将间隔时间划分为 0.5s,那么在出错之前它会再多一帧...
至于数据,我只是简单地将字节打包到 EventStream 帧的数据部分,就像它们在文件中一样。很明显,事件流打包是正确的(字节布局、CRC),否则我会收到错误提示,不是吗?
什么会向 AWSTrans 表明它不可解码?关于如何进行此操作还有其他想法吗?
感谢您的帮助...
这是执行打包的代码。完整版在这里(如果你敢...目前有点乱)https://pastebin.com/PKTj5xM2
Uint8List createEventStreamFrame(Uint8List audioChunk) {
final headers = [
EventStreamHeader(":content-type", 7, "application/octet-stream"),
EventStreamHeader(":event-type", 7, "AudioEvent"),
EventStreamHeader(":message-type", 7, "event")
];
final headersData = encodeEventStreamHeaders(headers);
final int totalLength = 16 + audioChunk.lengthInBytes + headersData.lengthInBytes;
// final prelude = [headersData.length, totalLength];
// print("Prelude: " + prelude.toString());
// Convert a 32b int to 4 bytes
List<int> int32ToBytes(int i) { return [(0xFF000000 & i) >> 24, (0x00FF0000 & i) >> 16, (0x0000FF00 & i) >> 8, (0x000000FF & i)]; }
final audioBytes = ByteData.sublistView(audioChunk);
var offset = 0;
var audioDataList = <int>[];
while (offset < audioBytes.lengthInBytes) {
audioDataList.add(audioBytes.getInt16(offset, Endian.little));
offset += 2;
}
final crc = CRC.crc32();
final messageBldr = BytesBuilder();
messageBldr.add(int32ToBytes(totalLength));
messageBldr.add(int32ToBytes(headersData.length));
// Now we can calc the CRC. We need to do it on the bytes, not the Ints
final preludeCrc = crc.calculate(messageBldr.toBytes());
// Continue adding data
messageBldr.add(int32ToBytes(preludeCrc));
messageBldr.add(headersData.toList());
// messageBldr.add(audioChunk.toList());
messageBldr.add(audioDataList);
final messageCrc = crc.calculate(messageBldr.toBytes().toList());
messageBldr.add(int32ToBytes(messageCrc));
final frame = messageBldr.toBytes();
//print("${frame.length} == $totalLength");
return frame;
}
这是我的建议(太长无法放入评论)。随时告诉我更新的信息,以便我进一步思考。
能否请您使用Wireshark查看传输的数据? (不需要,请参阅下一段替代方案)请检查它们,并查看线路上的数据(即正在传输的数据)是否有效。例如,手动记录那些数据字节并用一些音频播放器打开它。
或者,请不要使用 wireshark,而是将数据(您最初通过 websocket 传输的数据)写入本地文件。打开那个本地文件,看看它是否是一个有效的音频。 (p.s。注意一些音频播放器可以容忍格式错误)
其次,你试试看,如果把那个本来不错的wav文件的所有字节都放到一个websocket包里,能播放吗,还是会报错?
第三,这可能不是最佳做法...您知道,wav 是未压缩的并且非常大。您可能需要类似 AAC 文件格式的文件。或者,更高级的是 OPUS 格式。它们都适用于流式传输,例如,AAC 有一种称为 ADTS 的子格式,它可以打包到数据包中。
BadRequestException,至少在我的例子中,指的是帧编码不正确,而不是音频数据错误。
AWS 事件流编码详细信息为 here。
我在字节顺序和字节大小方面遇到了一些问题。您需要非常 bit-saavy 处理消息编码和音频缓冲区。音频需要为 16 位/有符号 (int)/little-endian (See here)。消息包装器中的那些长度参数是 32 位(4 字节)BIG endian。 ByteData
是你在 Dart 的朋友。这是我更新后的代码的一个片段:
final messageBytes = ByteData(totalLength);
...
for (var i=0; i<audioChunk.length; i++) {
messageBytes.setInt16(offset, audioChunk[i], Endian.little);
offset += 2;
}
请注意,16 位 int 实际上占用了 2 bytes 个位置。如果您不指定 Endian 样式,那么它将默认为您的系统,这将导致 header int 编码或音频数据错误...输输!
确保一切正确的最佳方法是编写 AWS 响应无论如何都需要的解码函数,然后解码编码帧并查看结果是否相同。使用 [-32000, -100, 0, 200 31000] 之类的 audo 测试数据,这样您就可以测试字节顺序等是否正确。
我正在使用 websockets 在 Dart/Flutter 中构建一个 Transcribe Streaming 应用程序。当我流式传输测试音频(从单声道、16kHz、16 位签名的小端 WAV 文件中提取)时,我得到...
BadRequestException: Could not decode the audio stream that you provided. Check that the audio stream is valid and try your request again.
作为测试,我正在使用文件流式传输音频。我每秒发送 32k 数据字节(大致模拟实时麦克风流)。如果我流式传输所有 0x00 或所有 0xFF 或随机字节,我什至会收到错误消息。如果我将块大小划分为 16k,将间隔时间划分为 0.5s,那么在出错之前它会再多一帧...
至于数据,我只是简单地将字节打包到 EventStream 帧的数据部分,就像它们在文件中一样。很明显,事件流打包是正确的(字节布局、CRC),否则我会收到错误提示,不是吗?
什么会向 AWSTrans 表明它不可解码?关于如何进行此操作还有其他想法吗?
感谢您的帮助...
这是执行打包的代码。完整版在这里(如果你敢...目前有点乱)https://pastebin.com/PKTj5xM2
Uint8List createEventStreamFrame(Uint8List audioChunk) {
final headers = [
EventStreamHeader(":content-type", 7, "application/octet-stream"),
EventStreamHeader(":event-type", 7, "AudioEvent"),
EventStreamHeader(":message-type", 7, "event")
];
final headersData = encodeEventStreamHeaders(headers);
final int totalLength = 16 + audioChunk.lengthInBytes + headersData.lengthInBytes;
// final prelude = [headersData.length, totalLength];
// print("Prelude: " + prelude.toString());
// Convert a 32b int to 4 bytes
List<int> int32ToBytes(int i) { return [(0xFF000000 & i) >> 24, (0x00FF0000 & i) >> 16, (0x0000FF00 & i) >> 8, (0x000000FF & i)]; }
final audioBytes = ByteData.sublistView(audioChunk);
var offset = 0;
var audioDataList = <int>[];
while (offset < audioBytes.lengthInBytes) {
audioDataList.add(audioBytes.getInt16(offset, Endian.little));
offset += 2;
}
final crc = CRC.crc32();
final messageBldr = BytesBuilder();
messageBldr.add(int32ToBytes(totalLength));
messageBldr.add(int32ToBytes(headersData.length));
// Now we can calc the CRC. We need to do it on the bytes, not the Ints
final preludeCrc = crc.calculate(messageBldr.toBytes());
// Continue adding data
messageBldr.add(int32ToBytes(preludeCrc));
messageBldr.add(headersData.toList());
// messageBldr.add(audioChunk.toList());
messageBldr.add(audioDataList);
final messageCrc = crc.calculate(messageBldr.toBytes().toList());
messageBldr.add(int32ToBytes(messageCrc));
final frame = messageBldr.toBytes();
//print("${frame.length} == $totalLength");
return frame;
}
这是我的建议(太长无法放入评论)。随时告诉我更新的信息,以便我进一步思考。
能否请您使用Wireshark查看传输的数据? (不需要,请参阅下一段替代方案)请检查它们,并查看线路上的数据(即正在传输的数据)是否有效。例如,手动记录那些数据字节并用一些音频播放器打开它。
或者,请不要使用 wireshark,而是将数据(您最初通过 websocket 传输的数据)写入本地文件。打开那个本地文件,看看它是否是一个有效的音频。 (p.s。注意一些音频播放器可以容忍格式错误)
其次,你试试看,如果把那个本来不错的wav文件的所有字节都放到一个websocket包里,能播放吗,还是会报错?
第三,这可能不是最佳做法...您知道,wav 是未压缩的并且非常大。您可能需要类似 AAC 文件格式的文件。或者,更高级的是 OPUS 格式。它们都适用于流式传输,例如,AAC 有一种称为 ADTS 的子格式,它可以打包到数据包中。
BadRequestException,至少在我的例子中,指的是帧编码不正确,而不是音频数据错误。
AWS 事件流编码详细信息为 here。
我在字节顺序和字节大小方面遇到了一些问题。您需要非常 bit-saavy 处理消息编码和音频缓冲区。音频需要为 16 位/有符号 (int)/little-endian (See here)。消息包装器中的那些长度参数是 32 位(4 字节)BIG endian。 ByteData
是你在 Dart 的朋友。这是我更新后的代码的一个片段:
final messageBytes = ByteData(totalLength);
...
for (var i=0; i<audioChunk.length; i++) {
messageBytes.setInt16(offset, audioChunk[i], Endian.little);
offset += 2;
}
请注意,16 位 int 实际上占用了 2 bytes 个位置。如果您不指定 Endian 样式,那么它将默认为您的系统,这将导致 header int 编码或音频数据错误...输输!
确保一切正确的最佳方法是编写 AWS 响应无论如何都需要的解码函数,然后解码编码帧并查看结果是否相同。使用 [-32000, -100, 0, 200 31000] 之类的 audo 测试数据,这样您就可以测试字节顺序等是否正确。