繁体   English   中英

AWS Transcribe Streaming BadRequestException:“无法解码音频 stream...”

[英]AWS Transcribe Streaming BadRequestException: "Could not decode the audio stream..."

我正在使用 websockets 在 Dart/Flutter 中构建一个 Transcribe Streaming 应用程序。 当我 stream 测试音频(从 mono、16kHz、16 位签名的小端 WAV 文件中提取)时,我得到...

BadRequestException:无法解码您提供的音频 stream。 检查音频 stream 是否有效,然后重试您的请求。

作为测试,我正在使用 stream 音频文件。 我每秒发送 32k 数据字节(大致模拟实时麦克风流)。 如果我 stream 所有 0x00 或所有 0xFF 或随机字节,我什至会收到错误消息。 如果我将块大小划分为 16k 并将间隔时间划分为 0.5s,那么在出错之前它会再多一帧......

至于数据,我只是简单地将字节打包到 EventStream 帧的数据部分,就像它们在文件中一样。 显然,事件 Stream 包装是正确的(字节布局、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;
}

BadRequestException,至少在我的例子中,指的是帧编码不正确,而不是音频数据错误。

AWS 事件 Stream 编码细节在这里

我在字节顺序和字节大小方面遇到了一些问题。 您需要对消息编码和音频缓冲区非常熟悉。 音频需要为 16 位/有符号 (int)/little-endian(参见此处)。 消息包装器中的那些长度参数是 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个字节的位置。 如果您不指定 Endian 样式,那么它将默认为您的系统,这将导致 header int 编码或音频数据出错......输了输了!

go 确保一切正确的最佳方法是编写 AWS 响应无论如何都需要的解码函数,然后解码编码帧并查看结果是否相同。 使用 [-32000, -100, 0, 200 31000] 之类的 audo 测试数据,这样您就可以测试字节顺序等是否正确。

这是我的建议(太长了,无法发表评论)。 请随时告诉我更新的信息,以便我进一步考虑。

能否请您使用 Wireshark 查看传输的数据? (不需要,请参阅下一段替代方案)请检查它们,并查看线路上的数据(即正在传输的数据)是否有效。 例如,手动记录那些数据字节并用一些音频播放器打开它。

或者,不使用 wireshark,请将数据(您最初通过 websocket 传输的数据)写入本地文件。 打开那个本地文件,看看它是否是一个有效的音频。 (注意一些音频播放器可以容忍格式错误)

其次,你试试看,如果把那个本来不错的wav文件的所有字节都放在一个websocket的数据包里,能不能播放,还是会报错?

第三,这可能不是最佳做法...您知道,wav 未压缩并且非常庞大。 您可能需要类似 AAC 文件格式的文件。 或者,更高级的是 OPUS 格式。 它们都适用于流式传输,例如,AAC 有一种称为 ADTS 的子格式,它可以打包到数据包中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM