簡體   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