You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中从BLE字节流构建WAV文件的问题及Header排查

问题描述

我从BLE设备接收PCM格式的音频字节数据,设备录制5秒音频后发送到安卓手机,参数如下:

  • 采样率:8kHz
  • 通道数:4
  • 采样位深:16位(每采样2字节)
  • 总采样数:160000

参考WAV格式规范构建WAV头,但播放时出错。字节流规则:

  • 忽略前3字节
  • 第3-10字节为数据大小
  • 后续数据排列:
    • 通道1第1个采样点:第0、1字节(0字节为LSB,1字节为MSB)
    • 通道2第1个采样点:第2、3字节(0字节为LSB,1字节为MSB)
    • ...以此类推

我的疑问:

  1. 以下构建的WAV头是否正确?
  2. 如何在Dart中实现上述字节流处理逻辑?

我构建的WAV头(十六进制,小端序,字符串除外)

52 49 46 46  “RIFF”
24 E2 04 00  FILE SIZE = 320044 - 8 = 320036
57 41 56 45  “WAVE”
66 6d 74 20  fmt    
10 00 00 00  size of fmt subchunk = 16    
01 00        pcm = 1
04 00        channels = 4
40 1F 00 00  sample rate = 8000 
00 FA 00 00  byteRate = 64000    
08 00        blockAlign = 8
10 00        bits per sample = 16    
64 61 74 61  “data”    
00 E2 04 00  size of data = 320000

转换为Uint8List的Dart代码

final header = Uint8List.fromList([
82,
73,
70,
70,
36,
226,
4,
0,
87,
65,
86,
69,
102,
109,
116,
32,
1,
0,
0,
0,
0,
1,
0,
4,
64,
31,
0,
0,
0,
250,
0,
0,
8,
0,
1,
0,
100,
97,
116,
97,
0,
226,
4,
0,
]);

播放错误日志

I/ExoPlayerImpl(19598): Init 5dd78f5 [ExoPlayerLib/2.17.1] [raven, Pixel 6 Pro, Google, 33]
W/io.platform.dev(19598): Accessing hidden method Landroid/media/AudioTrack;->getLatency()I (unsupported, reflection, allowed)
E/LoadTask(19598): Unexpected exception loading stream
E/LoadTask(19598):   java.lang.IllegalStateException
E/LoadTask(19598):       at com.google.android.exoplayer2.util.Assertions.checkState(Assertions.java:84)
E/LoadTask(19598):       at com.google.android.exoplayer2.extractor.wav.WavHeaderReader.readFormat(WavHeaderReader.java:100)
E/LoadTask(19598):       at com.google.android.exoplayer2.extractor.wav.WavExtractor.readFormat(WavExtractor.java:175)
E/LoadTask(19598):       at com.google.android.exoplayer2.extractor.wav.WavExtractor.read(WavExtractor.java:134)
E/LoadTask(19598):       at com.google.android.exoplayer2.source.BundledExtractorsAdapter.read(BundledExtractorsAdapter.java:127)
E/LoadTask(19598):       at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1042)
E/LoadTask(19598):       at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
E/LoadTask(19598):       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
E/LoadTask(19598):       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
E/LoadTask(19598):       at java.lang.Thread.run(Thread.java:1012)
E/ExoPlayerImplInternal(19598): Playback error
E/ExoPlayerImplInternal(19598):   com.google.android.exoplayer2.ExoPlaybackException: Source error

问题解决

1. WAV头的错误分析

你构建的WAV头存在参数顺序混乱的问题:fmt子块的标识之后,应该先放置子块大小(16),再依次是音频格式、通道数、采样率等参数,但你的代码打乱了这个顺序,导致ExoPlayer无法正确解析音频格式,触发异常。

2. 正确的Dart WAV头代码

按照标准WAV结构重新构建的头:

final correctHeader = Uint8List.fromList([
  // RIFF块
  82, 73, 70, 70, // "RIFF"标识
  36, 226, 4, 0, // 文件总大小:320044-8=320036(小端序)
  // WAVE块
  87, 65, 86, 69, // "WAVE"标识
  // fmt子块
  102, 109, 116, 32, // "fmt "标识
  16, 0, 0, 0, // fmt子块大小(固定16)
  1, 0, // PCM音频格式(值为1)
  4, 0, // 4通道
  64, 31, 0, 0, // 8000采样率(小端序:0x1F40=8000)
  0, 250, 0, 0, // 字节率:8000*4*16/8=64000(小端序:0xFA00=64000)
  8, 0, // 块对齐:4*16/8=8
  16, 0, // 16位采样位深
  // data子块
  100, 97, 116, 97, // "data"标识
  0, 226, 4, 0, // 数据大小:160000*2=320000(小端序:0x4E200=320000)
]);

3. Dart中处理BLE字节流的逻辑

直接按规则过滤原始数据,再拼接正确的WAV头即可(你的PCM字节顺序符合WAV小端要求,无需额外调整):

Uint8List processBLEAudioData(Uint8List rawData) {
  // 1. 跳过前3字节
  if (rawData.length < 3) throw ArgumentError("原始数据长度不足");
  Uint8List pcmData = rawData.sublist(3);
  
  // 2. 验证PCM数据长度(确保接收完整)
  if (pcmData.length != 320000) {
    throw ArgumentError("PCM数据长度错误:预期320000字节,实际${pcmData.length}字节");
  }
  
  // 3. 拼接WAV头和PCM数据
  Uint8List wavFile = Uint8List(correctHeader.length + pcmData.length);
  wavFile.setAll(0, correctHeader);
  wavFile.setAll(correctHeader.length, pcmData);
  
  return wavFile;
}

内容的提问来源于stack exchange,提问作者chessasuke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:18:11