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

Flutter获取PCM音频流写入文件含BOM头导致文件损坏的问题求助

Flutter获取PCM音频流写入文件含BOM头导致文件损坏的问题求助

我最近遇到一个棘手的问题:我的Flutter应用从后端获取PCM音频流,用Postman测试时能正常保存并通过ffplay播放,但Flutter本地保存的PCM文件却是损坏的,播放全是噪音。

问题核心对比

后端返回的是纯二进制PCM流,Postman保存的文件Hex开头是正常的原始数据:

03 00 01 00 FC FF FA FF F7 FF FB FF FA FF F8 FF F6 FF F6 FF ...

但Flutter保存的文件开头多了FF FE的BOM头,后续数据还出现了大量异常的重复片段(比如频繁出现A0 00),导致文件损坏:

FF FE 03 00 00 00 01 00 00 00 B3 00 A0 00 B7 00 A0 00 B8 00 A0 00 ...

相关代码片段

ApiService请求部分

static Future<http.StreamedResponse> getAudioById(int id) async {
  return await _authenticatedStreamRequest('/api/get/audioFile/$id', 'GET');
}

static Future<http.StreamedResponse> _authenticatedStreamRequest(
  String url, String method,
) async {
  String? accessToken = await SecureStorage.readSecureData('jwt_token');
  http.StreamedResponse response = await _makeStreamRequest(
    url, method, accessToken,
  );

  if (response.statusCode == 401) {
    debugPrint('Token expired, refreshing...');
    bool refreshed = await _refreshTokenIfNeeded();
    if (refreshed) {
      accessToken = await SecureStorage.readSecureData('jwt_token');
      response = await _makeStreamRequest(url, method, accessToken);
    }
  }
  return response;
}

static Future<http.StreamedResponse> _makeStreamRequest(
  String url, String method, String? token,
) async {
  final headers = <String, String>{};
  if (token != null) {
    headers['Authorization'] = 'Bearer $token';
    headers['Accept'] = 'application/octet-stream';
    // headers['Accept-Encoding'] = 'identity';
    headers['Connection'] = 'keep-alive';
    headers['Content-Type'] = 'application/octet-stream';
  }

  final request = http.Request(method, Uri.parse('$backendUrl$url'));
  request.headers.addAll(headers);
  request.followRedirects = true;

  try {
    final client = http.Client();
    final streamedResponse = await client
        .send(request)
        .timeout(
          const Duration(minutes: 15),
          onTimeout: () => throw Exception('Timeout fetching audio stream'),
        );
    return streamedResponse;
  } catch (e) {
    throw Exception('Error fetching audio stream: $e');
  }
}

本地保存文件部分

// 获取音频流响应
final audioDataResponse = await ApiService.getAudioById(id);
if (audioDataResponse == null) {
  throw Exception('Response null');
}

if (audioDataResponse.statusCode == 401 || audioDataResponse.statusCode == 404) {
  debugPrint('Error fetching audio data: ${audioDataResponse.statusCode}');
  return;
}
if (audioDataResponse.statusCode == 408) {
  debugPrint('Error occurred: ${audioDataResponse}');
  return;
}

try {
  final dir = await getTemporaryDirectory();
  final pcmFilePath = '${dir.path}/audio_$id.pcm';
  final pcmFile = File(pcmFilePath);

  if (await pcmFile.exists()) {
    await pcmFile.delete();
  }

  final sink = pcmFile.openWrite(mode: FileMode.writeOnly);
  await audioDataResponse.stream.pipe(sink);
  await sink.close();

  final checkBytes = await pcmFile.openRead(0, 20).first;
  debugPrint(
    'Gespeicherte PCM-Datei (direktes Streaming): ${checkBytes.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}',
  );
  debugPrint(
    'PCM-Datei erfolgreich per direktem Stream gespeichert: ${pcmFile.path}',
  );
} on Exception catch (e) {
  throw Exception('Fehler beim Speichern der PCM-Datei: $e');
}

我尝试过的调整

  • 启用/注释过Accept-Encoding: identity头,试图禁用自动压缩
  • 尝试移除请求的accept-encoding头
  • 确认请求头的Accept和Content-Type都设置为application/octet-stream

但问题依然存在,Flutter保存的文件始终带BOM头且数据异常。有没有朋友遇到过类似问题?或者能帮我排查下哪里出了问题?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 08:54:34